///|
fn longest_route_index(solution : @core.Solution) -> Int? {
if solution.routes.is_empty() {
return None
}
let mut chosen = 0
let mut longest = -1.0
for index, route in solution.routes {
if route.metrics.distance > longest {
chosen = index
longest = route.metrics.distance
}
}
Some(chosen)
}
///|
fn route_destroy_impl(
instance : @core.VrpInstance,
solution : @core.Solution,
remove_count : Int,
rng : @rng.Rng,
config : @core.SolveConfig,
) -> @core.Solution {
let route_index = match longest_route_index(solution) {
None => return solution.copy()
Some(index) => index
}
let route = solution.routes[route_index]
let pool = route.stops.copy()
if pool.is_empty() {
return solution.copy()
}
let target = remove_count.max(1).min(pool.length())
let picks : Array[Int] = []
for _ in 0.. @core.Solution {
let count = remove_count.max(1)
let assigned = solution.assigned_customers()
if assigned.is_empty() {
return solution.copy()
}
let seed = assigned[rng.next_int(assigned.length())]
let ranked = assigned.copy()
ranked.sort_by(fn(left, right) {
let left_customer = instance.customer(left)
let right_customer = instance.customer(right)
let left_score = instance.distance(seed, left) +
Double::abs(left_customer.demand() - instance.customer(seed).demand())
let right_score = instance.distance(seed, right) +
Double::abs(right_customer.demand() - instance.customer(seed).demand())
Double::compare(left_score, right_score)
})
remove_customers(
instance,
solution,
ranked[:count.min(ranked.length())].to_owned(),
config,
)
}
///|
fn customer_tightness(
instance : @core.VrpInstance,
customer_index : Int,
) -> Double {
let customer = instance.customer(customer_index)
customer.due_time() - customer.ready_time()
}
///|
fn time_critical_destroy_impl(
instance : @core.VrpInstance,
solution : @core.Solution,
remove_count : Int,
config : @core.SolveConfig,
) -> @core.Solution {
let ranked = solution.assigned_customers()
ranked.sort_by(fn(left, right) {
let order = Double::compare(
customer_tightness(instance, left),
customer_tightness(instance, right),
)
if order == 0 {
left - right
} else {
order
}
})
let take = remove_count.max(1).min(ranked.length())
remove_customers(instance, solution, ranked[:take].to_owned(), config)
}
///|
/// Removes a bounded fraction of assigned stops with a selected strategy.
pub fn destroy_fraction(
instance : @core.VrpInstance,
solution : @core.Solution,
operator : @core.DestroyOperator,
numerator : Int,
denominator : Int,
seed : Int,
config : @core.SolveConfig,
) -> @core.Solution {
let assigned = solution.assigned_customers().length()
let safe_denominator = denominator.max(1)
let count = (assigned * numerator.max(0) / safe_denominator)
.max(1)
.min(assigned)
destroy_solution(instance, solution, operator, count, seed~, config)
}