use solverforge_solver::CrossEntityDistanceMeter;
pub struct ProblemData {
pub capacity: i64,
pub depot: usize,
pub demands: Vec<i32>,
pub distance_matrix: Vec<Vec<i64>>,
pub time_windows: Vec<(i64, i64)>,
pub service_durations: Vec<i64>,
pub travel_times: Vec<Vec<i64>>,
pub vehicle_departure_time: i64,
}
pub trait VrpSolution {
fn vehicle_data_ptr(&self, entity_idx: usize) -> *const ProblemData;
fn vehicle_visits(&self, entity_idx: usize) -> &[usize];
fn vehicle_visits_mut(&mut self, entity_idx: usize) -> &mut Vec<usize>;
fn vehicle_count(&self) -> usize;
}
pub fn distance<S: VrpSolution>(plan: &S, i: usize, j: usize) -> i64 {
if plan.vehicle_count() == 0 {
return 0;
}
let data = unsafe { &*plan.vehicle_data_ptr(0) };
data.distance_matrix[i][j]
}
pub fn depot_for_entity<S: VrpSolution>(plan: &S, _entity_idx: usize) -> usize {
if plan.vehicle_count() == 0 {
return 0;
}
let data = unsafe { &*plan.vehicle_data_ptr(0) };
data.depot
}
pub fn depot_for_cw<S: VrpSolution>(plan: &S) -> usize {
if plan.vehicle_count() == 0 {
return 0;
}
let data = unsafe { &*plan.vehicle_data_ptr(0) };
data.depot
}
pub fn element_load<S: VrpSolution>(plan: &S, elem: usize) -> i64 {
if plan.vehicle_count() == 0 {
return 0;
}
let data = unsafe { &*plan.vehicle_data_ptr(0) };
data.demands[elem] as i64
}
pub fn capacity<S: VrpSolution>(plan: &S) -> i64 {
if plan.vehicle_count() == 0 {
return i64::MAX;
}
let data = unsafe { &*plan.vehicle_data_ptr(0) };
data.capacity
}
pub fn assign_route<S: VrpSolution>(plan: &mut S, entity_idx: usize, route: Vec<usize>) {
*plan.vehicle_visits_mut(entity_idx) = route;
}
pub fn get_route<S: VrpSolution>(plan: &S, entity_idx: usize) -> Vec<usize> {
plan.vehicle_visits(entity_idx).to_vec()
}
pub fn set_route<S: VrpSolution>(plan: &mut S, entity_idx: usize, route: Vec<usize>) {
*plan.vehicle_visits_mut(entity_idx) = route;
}
pub fn is_time_feasible<S: VrpSolution>(plan: &S, route: &[usize]) -> bool {
if route.is_empty() || plan.vehicle_count() == 0 {
return true;
}
let data = unsafe { &*plan.vehicle_data_ptr(0) };
check_time_feasible(route, data)
}
pub fn is_kopt_feasible<S: VrpSolution>(plan: &S, _entity_idx: usize, route: &[usize]) -> bool {
is_time_feasible(plan, route)
}
fn check_time_feasible(route: &[usize], data: &ProblemData) -> bool {
let mut current_time = data.vehicle_departure_time;
let mut prev = data.depot;
for &visit in route {
current_time += data.travel_times[prev][visit];
let (min_start, max_end) = data.time_windows[visit];
if current_time < min_start {
current_time = min_start;
}
let service_end = current_time + data.service_durations[visit];
if service_end > max_end {
return false;
}
current_time = service_end;
prev = visit;
}
true
}
#[derive(Clone, Default)]
pub struct MatrixDistanceMeter;
impl<S: VrpSolution> CrossEntityDistanceMeter<S> for MatrixDistanceMeter {
fn distance(
&self,
solution: &S,
src_entity: usize,
src_pos: usize,
dst_entity: usize,
dst_pos: usize,
) -> f64 {
let src_visits = solution.vehicle_visits(src_entity);
let dst_visits = solution.vehicle_visits(dst_entity);
if src_pos >= src_visits.len() || dst_pos >= dst_visits.len() {
return f64::INFINITY;
}
let data = unsafe { &*solution.vehicle_data_ptr(src_entity) };
data.distance_matrix[src_visits[src_pos]][dst_visits[dst_pos]] as f64
}
}
#[derive(Clone, Default)]
pub struct MatrixIntraDistanceMeter;
impl<S: VrpSolution> CrossEntityDistanceMeter<S> for MatrixIntraDistanceMeter {
fn distance(
&self,
solution: &S,
src_entity: usize,
src_pos: usize,
_dst_entity: usize,
dst_pos: usize,
) -> f64 {
let visits = solution.vehicle_visits(src_entity);
if src_pos >= visits.len() || dst_pos >= visits.len() {
return f64::INFINITY;
}
let data = unsafe { &*solution.vehicle_data_ptr(src_entity) };
data.distance_matrix[visits[src_pos]][visits[dst_pos]] as f64
}
}