use super::*;
use crate::models::common::{Cost, Schedule};
use crate::models::problem::*;
use crate::models::solution::*;
use crate::models::OP_START_MSG;
use crate::models::{LockOrder, Problem, Solution};
use crate::utils::Random;
use hashbrown::{HashMap, HashSet};
use std::ops::Deref;
use std::sync::Arc;
type ActivityPlace = crate::models::solution::Place;
pub fn create_insertion_context(problem: Arc<Problem>, random: Arc<dyn Random + Send + Sync>) -> InsertionContext {
let mut locked: HashSet<Job> = Default::default();
let mut reserved: HashSet<Job> = Default::default();
let mut ignored: HashSet<Job> = Default::default();
let mut unassigned: HashMap<Job, i32> = Default::default();
let mut routes: Vec<RouteContext> = Default::default();
let mut registry = Registry::new(&problem.fleet);
let state = Default::default();
let mut sequence_job_usage: HashMap<Job, usize> = Default::default();
problem.locks.iter().for_each(|lock| {
let actor = registry.available().find(|a| lock.condition.deref()(a.as_ref()));
match (actor, lock.is_lazy) {
(Some(actor), false) => {
registry.use_actor(&actor);
let mut route_ctx = RouteContext::new(actor);
let start = route_ctx.route.tour.start().unwrap_or_else(|| panic!(OP_START_MSG)).place.location;
let create_activity = |single: Arc<Single>, previous_location: usize| {
assert_eq!(single.places.len(), 1);
assert_eq!(single.places.first().unwrap().times.len(), 1);
let place = single.places.first().unwrap();
let time = single.places.first().unwrap().times.first().unwrap();
let time = time
.as_time_window()
.unwrap_or_else(|| panic!("Job with no time window is not supported in locks"));
Activity {
place: ActivityPlace {
location: place.location.unwrap_or(previous_location),
duration: place.duration,
time,
},
schedule: Schedule { arrival: 0.0, departure: 0.0 },
job: Some(single),
}
};
lock.details.iter().fold(start, |acc, detail| {
match detail.order {
LockOrder::Any => reserved.extend(detail.jobs.iter().cloned()),
_ => locked.extend(detail.jobs.iter().cloned()),
}
detail.jobs.iter().fold(acc, |acc, job| {
let activity = match job {
Job::Single(single) => create_activity(single.clone(), acc),
Job::Multi(multi) => {
let idx = sequence_job_usage.get(job).cloned().unwrap_or(0);
sequence_job_usage.insert(job.clone(), idx + 1);
create_activity(multi.jobs.get(idx).unwrap().clone(), acc)
}
};
let last_location = activity.place.location;
route_ctx.route_mut().tour.insert_last(activity);
last_location
})
});
problem.constraint.accept_route_state(&mut route_ctx);
routes.push(route_ctx);
}
(None, false) => {
unassigned.extend(lock.details.iter().flat_map(|d| d.jobs.iter().cloned().map(|j| (j, 0))));
}
(_, _) => {
locked.extend(lock.details.iter().flat_map(|d| d.jobs.iter().cloned()));
ignored.extend(lock.details.iter().flat_map(|d| d.jobs.iter().cloned()));
}
}
});
sequence_job_usage.iter().for_each(|(job, usage)| {
assert_eq!(job.to_multi().jobs.len(), *usage);
});
let required = problem
.jobs
.all()
.filter(|job| locked.get(job).is_none() && reserved.get(job).is_none() && unassigned.get(job).is_none())
.collect();
let registry = create_registry_context(&problem, registry);
let mut ctx = InsertionContext {
problem: problem.clone(),
solution: SolutionContext { required, ignored: vec![], unassigned, locked, routes, registry, state },
random,
};
problem.constraint.accept_solution_state(&mut ctx.solution);
ctx
}
pub fn create_insertion_context_from_solution(
problem: Arc<Problem>,
solution: (Solution, Option<Cost>),
random: Arc<dyn Random + Send + Sync>,
) -> InsertionContext {
let unassigned = solution.0.unassigned.iter().cloned().collect();
let locked = problem.locks.iter().fold(HashSet::new(), |mut acc, lock| {
acc.extend(lock.details.iter().flat_map(|d| d.jobs.iter().cloned()));
acc
});
let mut registry = solution.0.registry.deep_copy();
let mut routes: Vec<RouteContext> = Vec::new();
let state = Default::default();
solution.0.routes.iter().for_each(|route| {
if route.tour.has_jobs() {
routes.push(RouteContext { route: Arc::new(route.deep_copy()), state: Arc::new(RouteState::default()) });
} else {
registry.free_actor(&route.actor);
}
});
let registry = create_registry_context(&problem, registry);
let mut solution =
SolutionContext { required: vec![], ignored: vec![], unassigned, locked, routes, registry, state };
problem.constraint.accept_solution_state(&mut solution);
InsertionContext { problem, solution, random }
}
fn create_registry_context(problem: &Problem, registry: Registry) -> RegistryContext {
let modifier = problem.extras.get("route_modifier").and_then(|s| s.downcast_ref::<RouteModifier>());
if let Some(modifier) = modifier {
RegistryContext::new_with_modifier(registry, modifier)
} else {
RegistryContext::new(registry)
}
}