use crate::error::ValidationError;
use crate::pack::Bin;
use crate::sequence::Item;
pub fn validate_solution(
items: &[Item],
bins: &[Bin],
capacity: usize,
) -> std::result::Result<(), ValidationError> {
let mut seen = vec![false; items.len()];
for bin in bins {
let total: usize = bin.items.iter().map(|&id| items[id].len).sum();
if total > capacity {
return Err(ValidationError::CapacityExceeded {
bin_id: bin.id,
total,
capacity,
});
}
if bin.used != total {
return Err(ValidationError::AccountingMismatch { bin_id: bin.id });
}
for &id in &bin.items {
if seen[id] {
return Err(ValidationError::DuplicateItem { id });
}
seen[id] = true;
}
}
if seen.iter().any(|&s| !s) {
return Err(ValidationError::MissingItems);
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
fn items(lens: &[usize]) -> Vec<Item> {
lens.iter()
.enumerate()
.map(|(id, &len)| Item { id, len })
.collect()
}
#[test]
fn test_valid_solution() {
let itms = items(&[6, 4, 6, 4]);
let bins = vec![
Bin {
id: 0,
capacity: 10,
used: 10,
items: vec![0, 1].into(),
},
Bin {
id: 1,
capacity: 10,
used: 10,
items: vec![2, 3].into(),
},
];
assert!(validate_solution(&itms, &bins, 10).is_ok());
}
#[test]
fn test_capacity_exceeded() {
let itms = items(&[6, 6]);
let bins = vec![Bin {
id: 0,
capacity: 10,
used: 12,
items: vec![0, 1].into(),
}];
assert!(matches!(
validate_solution(&itms, &bins, 10),
Err(ValidationError::CapacityExceeded { .. })
));
}
#[test]
fn test_missing_items() {
let itms = items(&[5, 5, 5]);
let bins = vec![Bin {
id: 0,
capacity: 10,
used: 10,
items: vec![0, 1].into(),
}];
assert!(matches!(
validate_solution(&itms, &bins, 10),
Err(ValidationError::MissingItems)
));
}
#[test]
fn test_duplicate_item() {
let itms = items(&[5, 5]);
let bins = vec![
Bin {
id: 0,
capacity: 10,
used: 10,
items: vec![0, 1].into(),
},
Bin {
id: 1,
capacity: 10,
used: 5,
items: vec![0].into(),
},
];
assert!(matches!(
validate_solution(&itms, &bins, 10),
Err(ValidationError::DuplicateItem { id: 0 })
));
}
}