proxmox-resource-scheduling/tests/topsis.rs
Wolfgang Bumiller 5a50196a13 drop Topsis prefix of all the types in topsis::
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
2022-11-11 13:50:42 +01:00

290 lines
7.9 KiB
Rust

use anyhow::Error;
use proxmox_resource_scheduling::topsis::{rank_alternatives, Criteria, Criterion, Matrix};
#[test]
fn test_topsis_single_criterion() -> Result<(), Error> {
let criteria_pos = Criteria::new([Criterion::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(&Matrix::new(matrix.clone())?, &criteria_pos)?,
vec![0],
);
assert_eq!(
rank_alternatives(&Matrix::new(matrix)?, &criteria_neg)?,
vec![0],
);
let matrix = vec![[0.0], [2.0]];
assert_eq!(
rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_pos)?,
vec![1, 0],
);
assert_eq!(
rank_alternatives(&Matrix::new(matrix)?, &criteria_neg)?,
vec![0, 1],
);
let matrix = vec![[1.0], [2.0]];
assert_eq!(
rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_pos)?,
vec![1, 0],
);
assert_eq!(
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(&Matrix::new(matrix.clone())?, &criteria_pos)?,
vec![2, 4, 3, 1, 0],
);
assert_eq!(
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(&Matrix::new(matrix.clone())?, &criteria_pos)?,
vec![3, 0, 4, 2, 1],
);
assert_eq!(
rank_alternatives(&Matrix::new(matrix)?, &criteria_neg)?,
vec![1, 2, 4, 0, 3],
);
Ok(())
}
#[test]
fn test_topsis_two_criteria() -> Result<(), Error> {
let criteria_max_min = Criteria::new([
Criterion::new("max".to_string(), 1.0),
Criterion::new("min".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 = Criteria::new([
Criterion::new("min1".to_string(), -1.0),
Criterion::new("min2".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(&Matrix::new(matrix.clone())?, &criteria_max_min)?,
vec![0],
);
assert_eq!(
rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_min_max)?,
vec![0],
);
assert_eq!(
rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_min_min)?,
vec![0],
);
assert_eq!(
rank_alternatives(&Matrix::new(matrix)?, &criteria_max_max)?,
vec![0],
);
#[rustfmt::skip]
let matrix = vec![
[0.0, 1.0],
[1.0, 0.0],
[1.0, -1.0],
[1.0, 1.0],
[0.0, 0.0],
];
assert_eq!(
rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_max_min)?,
vec![2, 1, 4, 3, 0],
);
assert_eq!(
rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_min_max)?,
vec![0, 3, 4, 1, 2],
);
assert_eq!(
rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_min_min)?,
vec![2, 4, 1, 0, 3],
);
assert_eq!(
rank_alternatives(&Matrix::new(matrix)?, &criteria_max_max)?,
vec![3, 0, 1, 4, 2],
);
// This one was cross-checked with https://decision-radar.com/topsis rather than manually.
#[rustfmt::skip]
let matrix = vec![
[7.0, 4.0],
[1.0, 0.5],
[-1.0, -1.0],
[-8.5, 11.5],
[4.0, 7.0],
];
assert_eq!(
rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_max_min)?,
vec![0, 1, 4, 2, 3],
);
assert_eq!(
rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_min_max)?,
vec![3, 2, 4, 1, 0],
);
assert_eq!(
rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_min_min)?,
vec![2, 3, 1, 0, 4],
);
assert_eq!(
rank_alternatives(&Matrix::new(matrix)?, &criteria_max_max)?,
vec![4, 0, 1, 3, 2],
);
Ok(())
}
#[test]
fn test_topsis_three_criteria() -> Result<(), Error> {
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 = 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 = 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 = 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]
let matrix = vec![
[1.0, 0.0, 0.0],
[0.0, 1.0, 0.0],
[0.0, 0.0, 1.0],
];
assert_eq!(
rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_first)?,
vec![0, 1, 2],
);
assert_eq!(
rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_second)?,
vec![1, 0, 2],
);
assert_eq!(
rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_third)?,
vec![2, 0, 1],
);
assert_eq!(
rank_alternatives(&Matrix::new(matrix)?, &criteria_min)?,
vec![2, 1, 0],
);
#[rustfmt::skip]
let matrix = vec![
[1.0, 0.0, 0.0],
[0.0, 1.0, 0.0],
[0.0, 0.0, 1000.0],
];
// normalization ensures that it's still the same as above
assert_eq!(
rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_first)?,
vec![0, 1, 2],
);
assert_eq!(
rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_second)?,
vec![1, 0, 2],
);
assert_eq!(
rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_third)?,
vec![2, 0, 1],
);
assert_eq!(
rank_alternatives(&Matrix::new(matrix)?, &criteria_min)?,
vec![2, 1, 0],
);
#[rustfmt::skip]
let matrix = vec![
[-1.0, 0.0, 0.0],
[0.0, -1.0, 0.0],
[0.0, 0.0, 1.0],
];
assert_eq!(
rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_first)?,
vec![2, 1, 0],
);
assert_eq!(
rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_second)?,
vec![2, 0, 1],
);
assert_eq!(
rank_alternatives(&Matrix::new(matrix.clone())?, &criteria_third)?,
vec![2, 1, 0],
);
assert_eq!(
rank_alternatives(&Matrix::new(matrix)?, &criteria_min)?,
vec![0, 1, 2],
);
Ok(())
}
#[test]
fn test_nan() {
#[rustfmt::skip]
let matrix = vec![
[-1.0, 0.0, 0.0],
[0.0, -1.0, 0.0],
[0.0, f64::NAN, 1.0],
];
assert!(Matrix::new(matrix).is_err());
}
#[test]
fn test_zero() -> Result<(), Error> {
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 = 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]
let matrix = vec![
[0.0, 0.0, 0.0],
[0.0, 1.0, 0.0],
[0.0, 0.0, 1.0],
];
assert_eq!(
rank_alternatives(&Matrix::new(matrix)?, &criteria_first)?,
vec![1, 2, 0],
);
Ok(())
}