use super::*;
#[derive(Clone, Debug)]
struct Employee {
id: usize,
shift: Option<i32>,
}
#[derive(Clone, Debug)]
struct Solution {
employees: Vec<Employee>,
score: Option<SoftScore>,
}
impl PlanningSolution for Solution {
type Score = SoftScore;
fn score(&self) -> Option<Self::Score> {
self.score
}
fn set_score(&mut self, score: Option<Self::Score>) {
self.score = score;
}
}
fn get_shift(s: &Solution, idx: usize, _variable_index: usize) -> Option<i32> {
s.employees.get(idx).and_then(|e| e.shift)
}
fn set_shift(s: &mut Solution, idx: usize, _variable_index: usize, v: Option<i32>) {
if let Some(e) = s.employees.get_mut(idx) {
e.shift = v;
}
}
fn create_director(employees: Vec<Employee>) -> ScoreDirector<Solution, ()> {
let solution = Solution {
employees,
score: None,
};
let extractor = Box::new(EntityCollectionExtractor::new(
"Employee",
"employees",
|s: &Solution| &s.employees,
|s: &mut Solution| &mut s.employees,
));
let entity_desc = EntityDescriptor::new("Employee", TypeId::of::<Employee>(), "employees")
.with_extractor(extractor);
let descriptor =
SolutionDescriptor::new("Solution", TypeId::of::<Solution>()).with_entity(entity_desc);
ScoreDirector::simple(solution, descriptor, |s, _| s.employees.len())
}
#[test]
fn test_pillar_swap_all_entities() {
let mut director = create_director(vec![
Employee {
id: 0,
shift: Some(1),
},
Employee {
id: 1,
shift: Some(1),
},
Employee {
id: 2,
shift: Some(2),
},
Employee {
id: 3,
shift: Some(2),
},
]);
let m = PillarSwapMove::<Solution, i32>::new(
vec![0, 1],
vec![2, 3],
get_shift,
set_shift,
0,
"shift",
0,
);
assert!(m.is_doable(&director));
{
let mut recording = RecordingDirector::new(&mut director);
m.do_move(&mut recording);
assert_eq!(get_shift(recording.working_solution(), 0, 0), Some(2));
assert_eq!(get_shift(recording.working_solution(), 1, 0), Some(2));
assert_eq!(get_shift(recording.working_solution(), 2, 0), Some(1));
assert_eq!(get_shift(recording.working_solution(), 3, 0), Some(1));
recording.undo_changes();
}
assert_eq!(get_shift(director.working_solution(), 0, 0), Some(1));
assert_eq!(get_shift(director.working_solution(), 1, 0), Some(1));
assert_eq!(get_shift(director.working_solution(), 2, 0), Some(2));
assert_eq!(get_shift(director.working_solution(), 3, 0), Some(2));
let solution = director.working_solution();
assert_eq!(solution.employees[0].id, 0);
assert_eq!(solution.employees[1].id, 1);
assert_eq!(solution.employees[2].id, 2);
assert_eq!(solution.employees[3].id, 3);
}
#[test]
fn test_pillar_swap_same_value_not_doable() {
let director = create_director(vec![
Employee {
id: 0,
shift: Some(1),
},
Employee {
id: 1,
shift: Some(1),
},
]);
let m =
PillarSwapMove::<Solution, i32>::new(vec![0], vec![1], get_shift, set_shift, 0, "shift", 0);
assert!(!m.is_doable(&director));
}
#[test]
fn test_pillar_swap_empty_pillar_not_doable() {
let director = create_director(vec![Employee {
id: 0,
shift: Some(1),
}]);
let m =
PillarSwapMove::<Solution, i32>::new(vec![], vec![0], get_shift, set_shift, 0, "shift", 0);
assert!(!m.is_doable(&director));
}
#[test]
fn pillar_swap_tabu_identity_is_direction_stable() {
let mut director = create_director(vec![
Employee {
id: 0,
shift: Some(1),
},
Employee {
id: 1,
shift: Some(1),
},
Employee {
id: 2,
shift: Some(2),
},
Employee {
id: 3,
shift: Some(2),
},
]);
let forward = PillarSwapMove::<Solution, i32>::new(
vec![0, 1],
vec![2, 3],
get_shift,
set_shift,
0,
"shift",
0,
);
let forward_signature = forward.tabu_signature(&director);
{
let mut recording = RecordingDirector::new(&mut director);
forward.do_move(&mut recording);
}
let reverse_same_coordinates = PillarSwapMove::<Solution, i32>::new(
vec![0, 1],
vec![2, 3],
get_shift,
set_shift,
0,
"shift",
0,
);
let reverse_flipped_coordinates = PillarSwapMove::<Solution, i32>::new(
vec![2, 3],
vec![0, 1],
get_shift,
set_shift,
0,
"shift",
0,
);
let reverse_signature = reverse_same_coordinates.tabu_signature(&director);
let flipped_signature = reverse_flipped_coordinates.tabu_signature(&director);
assert_eq!(forward_signature.move_id, forward_signature.undo_move_id);
assert_eq!(forward_signature.move_id, reverse_signature.move_id);
assert_eq!(forward_signature.move_id, flipped_signature.move_id);
}