Sort residents by least flexibility first
This commit is contained in:
@@ -17,8 +17,8 @@ const YEAR: i32 = 2026;
|
|||||||
pub struct ToxicPair((ResidentId, ResidentId));
|
pub struct ToxicPair((ResidentId, ResidentId));
|
||||||
|
|
||||||
impl ToxicPair {
|
impl ToxicPair {
|
||||||
pub fn new(res_id_1: u8, res_id_2: u8) -> Self {
|
pub fn new(r_id_1: u8, r_id_2: u8) -> Self {
|
||||||
Self((ResidentId(res_id_1), ResidentId(res_id_2)))
|
Self((ResidentId(r_id_1), ResidentId(r_id_2)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn matches(&self, other: &ToxicPair) -> bool {
|
pub fn matches(&self, other: &ToxicPair) -> bool {
|
||||||
@@ -134,6 +134,14 @@ impl UserConfig {
|
|||||||
}
|
}
|
||||||
supply
|
supply
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn flexibility_map(&self) -> HashMap<ResidentId, u8> {
|
||||||
|
let mut map = HashMap::new();
|
||||||
|
for r in &self.residents {
|
||||||
|
map.insert(r.id, r.allowed_types.len() as u8);
|
||||||
|
}
|
||||||
|
map
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for UserConfig {
|
impl Default for UserConfig {
|
||||||
|
|||||||
@@ -47,8 +47,8 @@ impl Scheduler {
|
|||||||
tracker: &mut WorkloadTracker,
|
tracker: &mut WorkloadTracker,
|
||||||
) -> Result<bool, SearchError> {
|
) -> Result<bool, SearchError> {
|
||||||
schedule.prefill(&self.config);
|
schedule.prefill(&self.config);
|
||||||
for (slot, res_id) in schedule.0.iter() {
|
for (slot, r_id) in schedule.0.iter() {
|
||||||
tracker.insert(*res_id, &self.config, *slot);
|
tracker.insert(*r_id, &self.config, *slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: add validation
|
//TODO: add validation
|
||||||
@@ -59,10 +59,13 @@ impl Scheduler {
|
|||||||
.map(Slot::from)
|
.map(Slot::from)
|
||||||
.ok_or(SearchError::ScheduleFull)?;
|
.ok_or(SearchError::ScheduleFull)?;
|
||||||
|
|
||||||
let resident_ids = self.valid_residents(slot, schedule, tracker);
|
let mut valid_resident_ids = self.valid_residents(slot, schedule, tracker);
|
||||||
|
|
||||||
|
self.sort_residents(&mut valid_resident_ids, tracker, slot);
|
||||||
|
|
||||||
let solved_in_thread = AtomicBool::new(false);
|
let solved_in_thread = AtomicBool::new(false);
|
||||||
|
|
||||||
let sovled_state = resident_ids.par_iter().find_map_any(|&id| {
|
let sovled_state = valid_resident_ids.par_iter().find_map_any(|&id| {
|
||||||
let mut local_schedule = schedule.clone();
|
let mut local_schedule = schedule.clone();
|
||||||
let mut local_tracker = tracker.clone();
|
let mut local_tracker = tracker.clone();
|
||||||
|
|
||||||
@@ -127,14 +130,9 @@ impl Scheduler {
|
|||||||
return self.search(schedule, tracker, slot.next(), solved_in_thread);
|
return self.search(schedule, tracker, slot.next(), solved_in_thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut rng = SmallRng::from_rng(&mut rand::rng());
|
|
||||||
let mut valid_resident_ids = self.valid_residents(slot, schedule, tracker);
|
let mut valid_resident_ids = self.valid_residents(slot, schedule, tracker);
|
||||||
valid_resident_ids.shuffle(&mut rng);
|
|
||||||
valid_resident_ids.sort_by_key(|res_id| {
|
self.sort_residents(&mut valid_resident_ids, tracker, slot);
|
||||||
let type_count = tracker.current_shift_type_workload(res_id, slot.shift_type());
|
|
||||||
let workload = tracker.current_workload(res_id);
|
|
||||||
(type_count, workload)
|
|
||||||
});
|
|
||||||
|
|
||||||
for id in valid_resident_ids {
|
for id in valid_resident_ids {
|
||||||
schedule.insert(slot, id);
|
schedule.insert(slot, id);
|
||||||
@@ -151,12 +149,12 @@ impl Scheduler {
|
|||||||
Ok(false)
|
Ok(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn found_solution(&self, slot: Slot) -> bool {
|
fn found_solution(&self, slot: Slot) -> bool {
|
||||||
slot.greater_than(self.config.total_days)
|
slot.greater_than(self.config.total_days)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return all valid residents for the current slot
|
/// Return all valid residents for the current slot
|
||||||
pub fn valid_residents(
|
fn valid_residents(
|
||||||
&self,
|
&self,
|
||||||
slot: Slot,
|
slot: Slot,
|
||||||
schedule: &MonthlySchedule,
|
schedule: &MonthlySchedule,
|
||||||
@@ -195,4 +193,22 @@ impl Scheduler {
|
|||||||
.map(|r| r.id)
|
.map(|r| r.id)
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn sort_residents(
|
||||||
|
&self,
|
||||||
|
resident_ids: &mut Vec<ResidentId>,
|
||||||
|
tracker: &WorkloadTracker,
|
||||||
|
slot: Slot,
|
||||||
|
) {
|
||||||
|
let flex_map = self.config.flexibility_map();
|
||||||
|
let mut rng = SmallRng::from_rng(&mut rand::rng());
|
||||||
|
resident_ids.shuffle(&mut rng);
|
||||||
|
resident_ids.sort_by_key(|r_id| {
|
||||||
|
let type_workload = tracker.current_shift_type_workload(r_id, slot.shift_type());
|
||||||
|
let holiday_workload = tracker.current_holiday_workload(r_id);
|
||||||
|
let workload = tracker.current_workload(r_id);
|
||||||
|
let flex = flex_map.get(r_id).unwrap();
|
||||||
|
(flex, type_workload, workload, holiday_workload)
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user