drop Topsis prefix of all the types in topsis::

Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
Wolfgang Bumiller 2022-11-11 11:35:53 +01:00
parent 4ac19a0016
commit 5a50196a13
3 changed files with 102 additions and 106 deletions

View File

@ -1,7 +1,7 @@
use anyhow::Error; use anyhow::Error;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::topsis::TopsisMatrix; use crate::topsis;
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")] #[serde(rename_all = "kebab-case")]
@ -115,7 +115,7 @@ pub fn score_nodes_to_start_service(
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let scores = 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 Ok(scores
.into_iter() .into_iter()

View File

@ -17,7 +17,7 @@ fn l2_norm(values: &[f64]) -> f64 {
} }
/// A criterion that can be used when scoring with the TOPSIS algorithm. /// A criterion that can be used when scoring with the TOPSIS algorithm.
pub struct TopsisCriterion { pub struct Criterion {
/// Name of the criterion. /// Name of the criterion.
name: String, name: String,
/// The relative weight of the criterion. Is non-negative. /// The relative weight of the criterion. Is non-negative.
@ -26,8 +26,8 @@ pub struct TopsisCriterion {
maximize: bool, maximize: bool,
} }
impl TopsisCriterion { impl Criterion {
/// Construct a new `TopsisCriterion`. Use a negative weight if the value for the criterion /// Construct a new `Criterion`. Use a negative weight if the value for the criterion
/// should be minimized rather than maximized. /// should be minimized rather than maximized.
/// ///
/// Assumes that `weight` is finite. /// Assumes that `weight` is finite.
@ -38,7 +38,7 @@ impl TopsisCriterion {
(false, -weight) (false, -weight)
}; };
TopsisCriterion { Criterion {
name, name,
weight, weight,
maximize, maximize,
@ -46,14 +46,14 @@ impl TopsisCriterion {
} }
} }
/// A normalized array of `TopsisCriterion`. /// A normalized array of `Criterion`.
pub struct TopsisCriteria<const N_CRITERIA: usize>([TopsisCriterion; N_CRITERIA]); pub struct Criteria<const N_CRITERIA: usize>([Criterion; N_CRITERIA]);
impl<const N: usize> TopsisCriteria<N> { impl<const N: usize> Criteria<N> {
/// Create a new instance of normalized TOPSIS criteria. /// Create a new instance of normalized TOPSIS criteria.
/// ///
/// Assumes that the sum of weights can be calculated to a finite, non-zero value. /// Assumes that the sum of weights can be calculated to a finite, non-zero value.
pub fn new(mut criteria: [TopsisCriterion; N]) -> Result<Self, Error> { pub fn new(mut criteria: [Criterion; N]) -> Result<Self, Error> {
let divisor = criteria let divisor = criteria
.iter() .iter()
.fold(0.0, |sum, criterion| sum + criterion.weight); .fold(0.0, |sum, criterion| sum + criterion.weight);
@ -73,7 +73,7 @@ impl<const N: usize> TopsisCriteria<N> {
} }
} }
Ok(TopsisCriteria(criteria)) Ok(Criteria(criteria))
} }
/// Weigh each value according to the weight of its corresponding criterion. /// Weigh each value according to the weight of its corresponding criterion.
@ -86,9 +86,9 @@ impl<const N: usize> TopsisCriteria<N> {
} }
/// A normalized matrix used for scoring with the TOPSIS algorithm. /// A normalized matrix used for scoring with the TOPSIS algorithm.
pub struct TopsisMatrix<const N_CRITERIA: usize>(Vec<[f64; N_CRITERIA]>); pub struct Matrix<const N_CRITERIA: usize>(Vec<[f64; N_CRITERIA]>);
impl<const N: usize> TopsisMatrix<N> { impl<const N: usize> Matrix<N> {
/// Values of the matrix for the fixed critierion with index `index`. /// Values of the matrix for the fixed critierion with index `index`.
fn fixed_criterion(&self, index: usize) -> Vec<f64> { fn fixed_criterion(&self, index: usize) -> Vec<f64> {
self.0 self.0
@ -105,12 +105,12 @@ impl<const N: usize> TopsisMatrix<N> {
.collect::<Vec<&mut _>>() .collect::<Vec<&mut _>>()
} }
/// 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 /// Assumes that the sum of squares for each fixed criterion in `matrix` can be calculated to a
/// finite value. /// finite value.
pub fn new(matrix: Vec<[f64; N]>) -> Result<Self, Error> { pub fn new(matrix: Vec<[f64; N]>) -> Result<Self, Error> {
let mut matrix = TopsisMatrix(matrix); let mut matrix = Matrix(matrix);
for n in 0..N { for n in 0..N {
let divisor = l2_norm(&matrix.fixed_criterion(n)); let divisor = l2_norm(&matrix.fixed_criterion(n));
@ -129,17 +129,17 @@ impl<const N: usize> TopsisMatrix<N> {
} }
} }
/// 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. /// (respectively worst) value among the alternatives in the matrix for each single criterion.
struct TopsisIdealAlternatives<const N_CRITERIA: usize> { struct IdealAlternatives<const N_CRITERIA: usize> {
best: [f64; N_CRITERIA], best: [f64; N_CRITERIA],
worst: [f64; N_CRITERIA], worst: [f64; N_CRITERIA],
} }
impl<const N: usize> TopsisIdealAlternatives<N> { impl<const N: usize> IdealAlternatives<N> {
/// Compute the idealized alternatives from the given `matrix`. The `criteria` are required to know /// Compute the idealized alternatives from the given `matrix`. The `criteria` are required to know
/// if a critierion should be maximized or minimized. /// if a critierion should be maximized or minimized.
fn compute(matrix: &TopsisMatrix<N>, criteria: &TopsisCriteria<N>) -> Self { fn compute(matrix: &Matrix<N>, criteria: &Criteria<N>) -> Self {
let criteria = &criteria.0; let criteria = &criteria.0;
let mut best = [0.0; N]; let mut best = [0.0; N];
@ -170,10 +170,10 @@ impl<const N: usize> TopsisIdealAlternatives<N> {
/// alternative. Scores range from 0.0 to 1.0 and a low score indicates closness to the ideal worst /// 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. /// and/or distance to the ideal best alternatives.
pub fn score_alternatives<const N: usize>( pub fn score_alternatives<const N: usize>(
matrix: &TopsisMatrix<N>, matrix: &Matrix<N>,
criteria: &TopsisCriteria<N>, criteria: &Criteria<N>,
) -> Result<Vec<f64>, Error> { ) -> Result<Vec<f64>, Error> {
let ideal_alternatives = TopsisIdealAlternatives::compute(matrix, criteria); let ideal_alternatives = IdealAlternatives::compute(matrix, criteria);
let ideal_best = &ideal_alternatives.best; let ideal_best = &ideal_alternatives.best;
let ideal_worst = &ideal_alternatives.worst; let ideal_worst = &ideal_alternatives.worst;
@ -201,8 +201,8 @@ pub fn score_alternatives<const N: usize>(
/// Similar to `score_alternatives`, but returns the list of indices decreasing by score. /// Similar to `score_alternatives`, but returns the list of indices decreasing by score.
pub fn rank_alternatives<const N: usize>( pub fn rank_alternatives<const N: usize>(
matrix: &TopsisMatrix<N>, matrix: &Matrix<N>,
criteria: &TopsisCriteria<N>, criteria: &Criteria<N>,
) -> Result<Vec<usize>, Error> { ) -> Result<Vec<usize>, Error> {
let scores = score_alternatives(matrix, criteria)?; let scores = score_alternatives(matrix, criteria)?;
@ -243,10 +243,10 @@ macro_rules! criteria_struct {
} }
::lazy_static::lazy_static! { ::lazy_static::lazy_static! {
static ref $criteria_name: $crate::topsis::TopsisCriteria<$count_name> = static ref $criteria_name: $crate::topsis::Criteria<$count_name> =
$crate::topsis::TopsisCriteria::new([ $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(); .unwrap();

View File

@ -1,64 +1,60 @@
use anyhow::Error; use anyhow::Error;
use proxmox_resource_scheduling::topsis::{ use proxmox_resource_scheduling::topsis::{rank_alternatives, Criteria, Criterion, Matrix};
rank_alternatives, TopsisCriteria, TopsisCriterion, TopsisMatrix,
};
#[test] #[test]
fn test_topsis_single_criterion() -> Result<(), Error> { fn test_topsis_single_criterion() -> Result<(), Error> {
let criteria_pos = let criteria_pos = Criteria::new([Criterion::new("the one and only".to_string(), 1.0)])?;
TopsisCriteria::new([TopsisCriterion::new("the one and only".to_string(), 1.0)])?;
let criteria_neg = let criteria_neg = Criteria::new([Criterion::new("the one and only".to_string(), -1.0)])?;
TopsisCriteria::new([TopsisCriterion::new("the one and only".to_string(), -1.0)])?;
let matrix = vec![[0.0]]; let matrix = vec![[0.0]];
assert_eq!( assert_eq!(
rank_alternatives(&TopsisMatrix::new(matrix.clone())?, &criteria_pos)?, rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_pos)?,
vec![0], vec![0],
); );
assert_eq!( assert_eq!(
rank_alternatives(&TopsisMatrix::new(matrix)?, &criteria_neg)?, rank_alternatives(&Matrix::new(matrix)?, &criteria_neg)?,
vec![0], vec![0],
); );
let matrix = vec![[0.0], [2.0]]; let matrix = vec![[0.0], [2.0]];
assert_eq!( assert_eq!(
rank_alternatives(&TopsisMatrix::new(matrix.clone())?, &criteria_pos)?, rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_pos)?,
vec![1, 0], vec![1, 0],
); );
assert_eq!( assert_eq!(
rank_alternatives(&TopsisMatrix::new(matrix)?, &criteria_neg)?, rank_alternatives(&Matrix::new(matrix)?, &criteria_neg)?,
vec![0, 1], vec![0, 1],
); );
let matrix = vec![[1.0], [2.0]]; let matrix = vec![[1.0], [2.0]];
assert_eq!( assert_eq!(
rank_alternatives(&TopsisMatrix::new(matrix.clone())?, &criteria_pos)?, rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_pos)?,
vec![1, 0], vec![1, 0],
); );
assert_eq!( assert_eq!(
rank_alternatives(&TopsisMatrix::new(matrix)?, &criteria_neg)?, rank_alternatives(&Matrix::new(matrix)?, &criteria_neg)?,
vec![0, 1], vec![0, 1],
); );
let matrix = vec![[1.0], [2.0], [5.0], [3.0], [4.0]]; let matrix = vec![[1.0], [2.0], [5.0], [3.0], [4.0]];
assert_eq!( assert_eq!(
rank_alternatives(&TopsisMatrix::new(matrix.clone())?, &criteria_pos)?, rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_pos)?,
vec![2, 4, 3, 1, 0], vec![2, 4, 3, 1, 0],
); );
assert_eq!( assert_eq!(
rank_alternatives(&TopsisMatrix::new(matrix)?, &criteria_neg)?, rank_alternatives(&Matrix::new(matrix)?, &criteria_neg)?,
vec![0, 1, 3, 4, 2], vec![0, 1, 3, 4, 2],
); );
let matrix = vec![[-2.0], [-5.0], [-4.0], [1.0], [-3.0]]; let matrix = vec![[-2.0], [-5.0], [-4.0], [1.0], [-3.0]];
assert_eq!( assert_eq!(
rank_alternatives(&TopsisMatrix::new(matrix.clone())?, &criteria_pos)?, rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_pos)?,
vec![3, 0, 4, 2, 1], vec![3, 0, 4, 2, 1],
); );
assert_eq!( assert_eq!(
rank_alternatives(&TopsisMatrix::new(matrix)?, &criteria_neg)?, rank_alternatives(&Matrix::new(matrix)?, &criteria_neg)?,
vec![1, 2, 4, 0, 3], vec![1, 2, 4, 0, 3],
); );
@ -67,38 +63,38 @@ fn test_topsis_single_criterion() -> Result<(), Error> {
#[test] #[test]
fn test_topsis_two_criteria() -> Result<(), Error> { fn test_topsis_two_criteria() -> Result<(), Error> {
let criteria_max_min = TopsisCriteria::new([ let criteria_max_min = Criteria::new([
TopsisCriterion::new("max".to_string(), 1.0), Criterion::new("max".to_string(), 1.0),
TopsisCriterion::new("min".to_string(), -1.0), Criterion::new("min".to_string(), -1.0),
])?; ])?;
let criteria_min_max = TopsisCriteria::new([ let criteria_min_max = Criteria::new([
TopsisCriterion::new("min".to_string(), -1.0), Criterion::new("min".to_string(), -1.0),
TopsisCriterion::new("max".to_string(), 1.0), Criterion::new("max".to_string(), 1.0),
])?; ])?;
let criteria_min_min = TopsisCriteria::new([ let criteria_min_min = Criteria::new([
TopsisCriterion::new("min1".to_string(), -1.0), Criterion::new("min1".to_string(), -1.0),
TopsisCriterion::new("min2".to_string(), -1.0), Criterion::new("min2".to_string(), -1.0),
])?; ])?;
let criteria_max_max = TopsisCriteria::new([ let criteria_max_max = Criteria::new([
TopsisCriterion::new("max1".to_string(), 1.0), Criterion::new("max1".to_string(), 1.0),
TopsisCriterion::new("max2".to_string(), 1.0), Criterion::new("max2".to_string(), 1.0),
])?; ])?;
let matrix = vec![[0.0, 0.0]]; let matrix = vec![[0.0, 0.0]];
assert_eq!( assert_eq!(
rank_alternatives(&TopsisMatrix::new(matrix.clone())?, &criteria_max_min)?, rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_max_min)?,
vec![0], vec![0],
); );
assert_eq!( assert_eq!(
rank_alternatives(&TopsisMatrix::new(matrix.clone())?, &criteria_min_max)?, rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_min_max)?,
vec![0], vec![0],
); );
assert_eq!( assert_eq!(
rank_alternatives(&TopsisMatrix::new(matrix.clone())?, &criteria_min_min)?, rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_min_min)?,
vec![0], vec![0],
); );
assert_eq!( assert_eq!(
rank_alternatives(&TopsisMatrix::new(matrix)?, &criteria_max_max)?, rank_alternatives(&Matrix::new(matrix)?, &criteria_max_max)?,
vec![0], vec![0],
); );
@ -111,19 +107,19 @@ fn test_topsis_two_criteria() -> Result<(), Error> {
[0.0, 0.0], [0.0, 0.0],
]; ];
assert_eq!( 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], vec![2, 1, 4, 3, 0],
); );
assert_eq!( 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], vec![0, 3, 4, 1, 2],
); );
assert_eq!( 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], vec![2, 4, 1, 0, 3],
); );
assert_eq!( assert_eq!(
rank_alternatives(&TopsisMatrix::new(matrix)?, &criteria_max_max)?, rank_alternatives(&Matrix::new(matrix)?, &criteria_max_max)?,
vec![3, 0, 1, 4, 2], vec![3, 0, 1, 4, 2],
); );
@ -137,19 +133,19 @@ fn test_topsis_two_criteria() -> Result<(), Error> {
[4.0, 7.0], [4.0, 7.0],
]; ];
assert_eq!( 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], vec![0, 1, 4, 2, 3],
); );
assert_eq!( 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], vec![3, 2, 4, 1, 0],
); );
assert_eq!( 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], vec![2, 3, 1, 0, 4],
); );
assert_eq!( assert_eq!(
rank_alternatives(&TopsisMatrix::new(matrix)?, &criteria_max_max)?, rank_alternatives(&Matrix::new(matrix)?, &criteria_max_max)?,
vec![4, 0, 1, 3, 2], vec![4, 0, 1, 3, 2],
); );
@ -158,25 +154,25 @@ fn test_topsis_two_criteria() -> Result<(), Error> {
#[test] #[test]
fn test_topsis_three_criteria() -> Result<(), Error> { fn test_topsis_three_criteria() -> Result<(), Error> {
let criteria_first = TopsisCriteria::new([ let criteria_first = Criteria::new([
TopsisCriterion::new("more".to_string(), 10.0), Criterion::new("more".to_string(), 10.0),
TopsisCriterion::new("less".to_string(), 0.2), Criterion::new("less".to_string(), 0.2),
TopsisCriterion::new("least".to_string(), 0.1), Criterion::new("least".to_string(), 0.1),
])?; ])?;
let criteria_second = TopsisCriteria::new([ let criteria_second = Criteria::new([
TopsisCriterion::new("less".to_string(), 0.2), Criterion::new("less".to_string(), 0.2),
TopsisCriterion::new("more".to_string(), 10.0), Criterion::new("more".to_string(), 10.0),
TopsisCriterion::new("least".to_string(), 0.1), Criterion::new("least".to_string(), 0.1),
])?; ])?;
let criteria_third = TopsisCriteria::new([ let criteria_third = Criteria::new([
TopsisCriterion::new("less".to_string(), 0.2), Criterion::new("less".to_string(), 0.2),
TopsisCriterion::new("least".to_string(), 0.1), Criterion::new("least".to_string(), 0.1),
TopsisCriterion::new("more".to_string(), 10.0), Criterion::new("more".to_string(), 10.0),
])?; ])?;
let criteria_min = TopsisCriteria::new([ let criteria_min = Criteria::new([
TopsisCriterion::new("most".to_string(), -10.0), Criterion::new("most".to_string(), -10.0),
TopsisCriterion::new("more".to_string(), -5.0), Criterion::new("more".to_string(), -5.0),
TopsisCriterion::new("less".to_string(), 0.1), Criterion::new("less".to_string(), 0.1),
])?; ])?;
#[rustfmt::skip] #[rustfmt::skip]
@ -186,19 +182,19 @@ fn test_topsis_three_criteria() -> Result<(), Error> {
[0.0, 0.0, 1.0], [0.0, 0.0, 1.0],
]; ];
assert_eq!( assert_eq!(
rank_alternatives(&TopsisMatrix::new(matrix.clone())?, &criteria_first)?, rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_first)?,
vec![0, 1, 2], vec![0, 1, 2],
); );
assert_eq!( assert_eq!(
rank_alternatives(&TopsisMatrix::new(matrix.clone())?, &criteria_second)?, rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_second)?,
vec![1, 0, 2], vec![1, 0, 2],
); );
assert_eq!( assert_eq!(
rank_alternatives(&TopsisMatrix::new(matrix.clone())?, &criteria_third)?, rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_third)?,
vec![2, 0, 1], vec![2, 0, 1],
); );
assert_eq!( assert_eq!(
rank_alternatives(&TopsisMatrix::new(matrix)?, &criteria_min)?, rank_alternatives(&Matrix::new(matrix)?, &criteria_min)?,
vec![2, 1, 0], 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 // normalization ensures that it's still the same as above
assert_eq!( assert_eq!(
rank_alternatives(&TopsisMatrix::new(matrix.clone())?, &criteria_first)?, rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_first)?,
vec![0, 1, 2], vec![0, 1, 2],
); );
assert_eq!( assert_eq!(
rank_alternatives(&TopsisMatrix::new(matrix.clone())?, &criteria_second)?, rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_second)?,
vec![1, 0, 2], vec![1, 0, 2],
); );
assert_eq!( assert_eq!(
rank_alternatives(&TopsisMatrix::new(matrix.clone())?, &criteria_third)?, rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_third)?,
vec![2, 0, 1], vec![2, 0, 1],
); );
assert_eq!( assert_eq!(
rank_alternatives(&TopsisMatrix::new(matrix)?, &criteria_min)?, rank_alternatives(&Matrix::new(matrix)?, &criteria_min)?,
vec![2, 1, 0], vec![2, 1, 0],
); );
@ -233,19 +229,19 @@ fn test_topsis_three_criteria() -> Result<(), Error> {
[0.0, 0.0, 1.0], [0.0, 0.0, 1.0],
]; ];
assert_eq!( assert_eq!(
rank_alternatives(&TopsisMatrix::new(matrix.clone())?, &criteria_first)?, rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_first)?,
vec![2, 1, 0], vec![2, 1, 0],
); );
assert_eq!( assert_eq!(
rank_alternatives(&TopsisMatrix::new(matrix.clone())?, &criteria_second)?, rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_second)?,
vec![2, 0, 1], vec![2, 0, 1],
); );
assert_eq!( assert_eq!(
rank_alternatives(&TopsisMatrix::new(matrix.clone())?, &criteria_third)?, rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_third)?,
vec![2, 1, 0], vec![2, 1, 0],
); );
assert_eq!( assert_eq!(
rank_alternatives(&TopsisMatrix::new(matrix)?, &criteria_min)?, rank_alternatives(&Matrix::new(matrix)?, &criteria_min)?,
vec![0, 1, 2], vec![0, 1, 2],
); );
@ -260,22 +256,22 @@ fn test_nan() {
[0.0, -1.0, 0.0], [0.0, -1.0, 0.0],
[0.0, f64::NAN, 1.0], [0.0, f64::NAN, 1.0],
]; ];
assert!(TopsisMatrix::new(matrix).is_err()); assert!(Matrix::new(matrix).is_err());
} }
#[test] #[test]
fn test_zero() -> Result<(), Error> { fn test_zero() -> Result<(), Error> {
let criteria_zero = TopsisCriteria::new([ let criteria_zero = Criteria::new([
TopsisCriterion::new("z".to_string(), 0.0), Criterion::new("z".to_string(), 0.0),
TopsisCriterion::new("e".to_string(), 0.0), Criterion::new("e".to_string(), 0.0),
TopsisCriterion::new("ro".to_string(), 0.0), Criterion::new("ro".to_string(), 0.0),
]); ]);
assert!(criteria_zero.is_err()); assert!(criteria_zero.is_err());
let criteria_first = TopsisCriteria::new([ let criteria_first = Criteria::new([
TopsisCriterion::new("more".to_string(), 10.0), Criterion::new("more".to_string(), 10.0),
TopsisCriterion::new("less".to_string(), 0.2), Criterion::new("less".to_string(), 0.2),
TopsisCriterion::new("least".to_string(), 0.1), Criterion::new("least".to_string(), 0.1),
])?; ])?;
#[rustfmt::skip] #[rustfmt::skip]
@ -285,7 +281,7 @@ fn test_zero() -> Result<(), Error> {
[0.0, 0.0, 1.0], [0.0, 0.0, 1.0],
]; ];
assert_eq!( assert_eq!(
rank_alternatives(&TopsisMatrix::new(matrix)?, &criteria_first)?, rank_alternatives(&Matrix::new(matrix)?, &criteria_first)?,
vec![1, 2, 0], vec![1, 2, 0],
); );