///|
/// Computes the distance between two points under this metric.
pub fn DistanceMetric::distance(
self : DistanceMetric,
ax : Double,
ay : Double,
bx : Double,
by : Double,
) -> Double {
let dx = ax - bx
let dy = ay - by
match self {
DistanceMetric::Euclidean => Double::sqrt(dx * dx + dy * dy)
DistanceMetric::RoundedEuclidean =>
Double::round(Double::sqrt(dx * dx + dy * dy))
DistanceMetric::Manhattan => Double::abs(dx) + Double::abs(dy)
DistanceMetric::Chebyshev => Double::max(Double::abs(dx), Double::abs(dy))
}
}
///|
/// Returns the conventional name used by benchmark formats.
pub fn DistanceMetric::name(self : DistanceMetric) -> String {
match self {
DistanceMetric::Euclidean => "EUCLIDEAN"
DistanceMetric::RoundedEuclidean => "EUC_2D"
DistanceMetric::Manhattan => "MANHATTAN"
DistanceMetric::Chebyshev => "CHEBYSHEV"
}
}
///|
/// All built-in metrics are symmetric and satisfy d(a, a) = 0.
pub fn DistanceMetric::is_symmetric(self : DistanceMetric) -> Bool {
match self {
DistanceMetric::Euclidean => true
DistanceMetric::RoundedEuclidean => true
DistanceMetric::Manhattan => true
DistanceMetric::Chebyshev => true
}
}
///|
/// Returns a compact summary of a matrix for regression tests and diagnostics.
pub fn VrpInstance::distance_summary(
self : VrpInstance,
) -> (Double, Double, Double) {
let mut minimum = 1_000_000_000.0
let mut maximum = 0.0
let mut total = 0.0
let mut count = 0
for row in self.distance_matrix {
for value in row {
if value > 0.0 {
minimum = Double::min(minimum, value)
maximum = Double::max(maximum, value)
total += value
count += 1
}
}
}
let average = if count == 0 { 0.0 } else { total / Double::from_int(count) }
(minimum, maximum, average)
}
///|
/// Returns the nearest customer indices, ordered by distance from a point.
pub fn VrpInstance::nearest_customers(
self : VrpInstance,
from_index : Int,
limit : Int,
) -> Array[Int] {
let ranked : Array[(Int, Double)] = []
for index in 0..