///|
/// A finite-domain friendly vehicle-routing toolkit.
///
/// The routing layer deliberately keeps the data representation compact and
/// deterministic. It is useful before a full solver model is posted: a
/// planner can validate input, construct a feasible seed plan, measure it,
/// and then use the resulting route as a warm start for a richer model.
pub struct RoutingPoint {
  id : Int
  x : Int
  y : Int
  demand : Int
  service : Int
  ready : Int
  due : Int
}

///|
/// Create a customer or depot point with a wide time window.
pub fn routing_point(id : Int, x : Int, y : Int, demand : Int) -> RoutingPoint {
  { id, x, y, demand, service: 0, ready: 0, due: 2147483647 }
}

///|
/// Return a copy with a service duration.
pub fn RoutingPoint::with_service(
  self : RoutingPoint,
  service : Int,
) -> RoutingPoint {
  { ..self, service: if service < 0 { 0 } else { service } }
}

///|
/// Return a copy with a time window.
pub fn RoutingPoint::with_window(
  self : RoutingPoint,
  ready : Int,
  due : Int,
) -> RoutingPoint {
  { ..self, ready, due }
}

///|
/// Read the stable customer identifier.
pub fn RoutingPoint::id(self : RoutingPoint) -> Int {
  self.id
}

///|
/// Read the horizontal coordinate.
pub fn RoutingPoint::x(self : RoutingPoint) -> Int {
  self.x
}

///|
/// Read the vertical coordinate.
pub fn RoutingPoint::y(self : RoutingPoint) -> Int {
  self.y
}

///|
/// Read the demand.
pub fn RoutingPoint::demand(self : RoutingPoint) -> Int {
  self.demand
}

///|
/// Read the service duration.
pub fn RoutingPoint::service(self : RoutingPoint) -> Int {
  self.service
}

///|
/// Return whether a point has a valid time window.
pub fn RoutingPoint::valid_window(self : RoutingPoint) -> Bool {
  self.ready <= self.due
}

///|
/// A validated routing instance with an integer distance matrix.
pub struct RoutingInstance {
  points : Array[RoutingPoint]
  depot : Int
  vehicles : Int
  capacities : Array[Int]
  distances : Array[Array[Int]]
}

///|
/// Build a routing instance from customer points and vehicle capacities.
pub fn routing_instance(
  points : Array[RoutingPoint],
  depot : Int,
  capacities : Array[Int],
) -> RoutingInstance? {
  if points.length() < 2 || depot < 0 || depot >= points.length() {
    return None
  }
  if capacities.length() < 1 {
    return None
  }
  for point in points {
    if point.demand < 0 || !point.valid_window() {
      return None
    }
  }
  for capacity in capacities {
    if capacity < 0 {
      return None
    }
  }
  let distances : Array[Array[Int]] = []
  for left in points {
    let row : Array[Int] = []
    for right in points {
      row.push(abs_int(left.x - right.x) + abs_int(left.y - right.y))
    }
    distances.push(row)
  }
  Some({
    points: points.copy(),
    depot,
    vehicles: capacities.length(),
    capacities: capacities.copy(),
    distances,
  })
}

///|
/// Build a square instance with an explicit distance matrix.
pub fn routing_instance_with_distances(
  points : Array[RoutingPoint],
  depot : Int,
  capacities : Array[Int],
  distances : Array[Array[Int]],
) -> RoutingInstance? {
  if points.length() < 2 ||
    depot < 0 ||
    depot >= points.length() ||
    capacities.length() < 1 {
    return None
  }
  if distances.length() != points.length() {
    return None
  }
  for row in distances {
    if row.length() != points.length() {
      return None
    }
    for value in row {
      if value < 0 {
        return None
      }
    }
  }
  for point in points {
    if point.demand < 0 || !point.valid_window() {
      return None
    }
  }
  for capacity in capacities {
    if capacity < 0 {
      return None
    }
  }
  Some({
    points: points.copy(),
    depot,
    vehicles: capacities.length(),
    capacities: capacities.copy(),
    distances: distances.map(row => row.copy()),
  })
}

///|
/// Number of locations including the depot.
pub fn RoutingInstance::location_count(self : RoutingInstance) -> Int {
  self.points.length()
}

///|
/// Number of vehicles.
pub fn RoutingInstance::vehicle_count(self : RoutingInstance) -> Int {
  self.vehicles
}

///|
/// Return the depot location identifier.
pub fn RoutingInstance::depot(self : RoutingInstance) -> Int {
  self.depot
}

///|
/// Read one point.
pub fn RoutingInstance::point(self : RoutingInstance, id : Int) -> RoutingPoint {
  if id < 0 || id >= self.points.length() {
    abort("routing point is outside the instance")
  }
  self.points[id]
}

///|
/// Read one vehicle capacity.
pub fn RoutingInstance::capacity(self : RoutingInstance, vehicle : Int) -> Int {
  if vehicle < 0 || vehicle >= self.capacities.length() {
    abort("routing vehicle is outside the instance")
  }
  self.capacities[vehicle]
}

///|
/// Return the directed distance between two locations.
pub fn RoutingInstance::distance(
  self : RoutingInstance,
  from : Int,
  to : Int,
) -> Int {
  if from < 0 ||
    from >= self.points.length() ||
    to < 0 ||
    to >= self.points.length() {
    abort("routing distance endpoint is outside the instance")
  }
  self.distances[from][to]
}

///|
/// Return all customer identifiers, excluding the depot.
pub fn RoutingInstance::customers(self : RoutingInstance) -> Array[Int] {
  let result : Array[Int] = []
  for id in 0.. Int {
  let mut result = 0
  for point in self.points {
    if point.id != self.points[self.depot].id {
      result += point.demand
    }
  }
  result
}

///|
/// A route is represented without an implicit depot in its stop list.
pub struct VehicleRoute {
  vehicle : Int
  stops : Array[Int]
}

///|
/// Create an empty route for a vehicle.
pub fn vehicle_route(vehicle : Int) -> VehicleRoute {
  { vehicle, stops: [] }
}

///|
/// Create a route from a stop sequence.
pub fn vehicle_route_from(vehicle : Int, stops : Array[Int]) -> VehicleRoute {
  { vehicle, stops: stops.copy() }
}

///|
/// Read the vehicle index.
pub fn VehicleRoute::vehicle(self : VehicleRoute) -> Int {
  self.vehicle
}

///|
/// Read a copied stop sequence.
pub fn VehicleRoute::stops(self : VehicleRoute) -> Array[Int] {
  self.stops.copy()
}

///|
/// Number of customer visits.
pub fn VehicleRoute::length(self : VehicleRoute) -> Int {
  self.stops.length()
}

///|
/// Append a customer when it has not already been used in this route.
pub fn VehicleRoute::push_unique(self : VehicleRoute, stop : Int) -> Bool {
  if self.stops.contains(stop) {
    return false
  }
  self.stops.push(stop)
  true
}

///|
/// Insert a customer at a bounded position.
pub fn VehicleRoute::insert(
  self : VehicleRoute,
  position : Int,
  stop : Int,
) -> Bool {
  if position < 0 || position > self.stops.length() || self.stops.contains(stop) {
    return false
  }
  self.stops.push(0)
  let mut index = self.stops.length() - 1
  while index > position {
    self.stops[index] = self.stops[index - 1]
    index -= 1
  }
  self.stops[position] = stop
  true
}

///|
/// Remove a stop and return whether it was found.
pub fn VehicleRoute::remove(self : VehicleRoute, stop : Int) -> Bool {
  let mut index = 0
  while index < self.stops.length() {
    if self.stops[index] == stop {
      while index + 1 < self.stops.length() {
        self.stops[index] = self.stops[index + 1]
        index += 1
      }
      ignore(self.stops.pop())
      return true
    }
    index += 1
  }
  false
}

///|
/// Reverse a bounded inclusive segment for 2-opt neighborhoods.
pub fn VehicleRoute::reverse_segment(
  self : VehicleRoute,
  left : Int,
  right : Int,
) -> Bool {
  if left < 0 || right >= self.stops.length() || left >= right {
    return false
  }
  let mut low = left
  let mut high = right
  while low < high {
    let temporary = self.stops[low]
    self.stops[low] = self.stops[high]
    self.stops[high] = temporary
    low += 1
    high -= 1
  }
  true
}

///|
/// A complete multi-vehicle plan.
pub struct RoutingPlan {
  routes : Array[VehicleRoute]
}

///|
/// Create an empty plan with one route per vehicle.
pub fn routing_plan(vehicle_count : Int) -> RoutingPlan {
  let routes : Array[VehicleRoute] = []
  for vehicle in 0.. Int {
  self.routes.length()
}

///|
/// Read a route.
pub fn RoutingPlan::route(self : RoutingPlan, vehicle : Int) -> VehicleRoute {
  if vehicle < 0 || vehicle >= self.routes.length() {
    abort("routing plan vehicle is outside the plan")
  }
  self.routes[vehicle]
}

///|
/// Return copied routes.
pub fn RoutingPlan::routes(self : RoutingPlan) -> Array[VehicleRoute] {
  self.routes.map(route => vehicle_route_from(route.vehicle, route.stops))
}

///|
/// Append a stop to a vehicle route.
pub fn RoutingPlan::append(
  self : RoutingPlan,
  vehicle : Int,
  stop : Int,
) -> Bool {
  if vehicle < 0 || vehicle >= self.routes.length() {
    return false
  }
  self.routes[vehicle].push_unique(stop)
}

///|
/// Locate a customer in the plan, returning vehicle and position.
pub fn RoutingPlan::locate(self : RoutingPlan, stop : Int) -> (Int, Int)? {
  for vehicle, route in self.routes {
    for position, candidate in route.stops {
      if candidate == stop {
        return Some((vehicle, position))
      }
    }
  }
  None
}

///|
/// Return all visits in vehicle order.
pub fn RoutingPlan::visited(self : RoutingPlan) -> Array[Int] {
  let result : Array[Int] = []
  for route in self.routes {
    for stop in route.stops {
      result.push(stop)
    }
  }
  result
}

///|
/// Return a stable route string useful for logs and benchmark snapshots.
pub fn RoutingPlan::describe(self : RoutingPlan) -> String {
  let builder = StringBuilder()
  for vehicle, route in self.routes {
    if vehicle > 0 {
      builder.write_char('\n')
    }
    builder.write_string("vehicle \{vehicle}: depot")
    for stop in route.stops {
      builder.write_string(" -> \{stop}")
    }
    builder.write_string(" -> depot")
  }
  builder.to_string()
}

///|
/// Route distance including the depot departure and return.
pub fn route_distance(instance : RoutingInstance, route : VehicleRoute) -> Int {
  let mut result = 0
  let mut previous = instance.depot
  for stop in route.stops {
    result += instance.distance(previous, stop)
    previous = stop
  }
  result + instance.distance(previous, instance.depot)
}

///|
/// Sum customer demand on a route.
pub fn route_load(instance : RoutingInstance, route : VehicleRoute) -> Int {
  let mut result = 0
  for stop in route.stops {
    if stop >= 0 && stop < instance.points.length() {
      result += instance.points[stop].demand
    }
  }
  result
}

///|
/// Return the route's service time excluding travel.
pub fn route_service(instance : RoutingInstance, route : VehicleRoute) -> Int {
  let mut result = 0
  for stop in route.stops {
    if stop >= 0 && stop < instance.points.length() {
      result += instance.points[stop].service
    }
  }
  result
}

///|
/// Arrival and departure times for a route under its time windows.
pub fn route_arrivals(
  instance : RoutingInstance,
  route : VehicleRoute,
) -> Array[Int] {
  let result : Array[Int] = []
  let mut clock = 0
  let mut previous = instance.depot
  for stop in route.stops {
    clock += instance.distance(previous, stop)
    let point = instance.points[stop]
    if clock < point.ready {
      clock = point.ready
    }
    result.push(clock)
    clock += point.service
    previous = stop
  }
  result
}

///|
/// Validate a single route and return a stable error code.
pub fn validate_route(
  instance : RoutingInstance,
  route : VehicleRoute,
) -> String? {
  if route.vehicle < 0 || route.vehicle >= instance.vehicles {
    return Some("vehicle-out-of-range")
  }
  for stop in route.stops {
    if stop < 0 || stop >= instance.points.length() || stop == instance.depot {
      return Some("stop-out-of-range-or-depot")
    }
  }
  for left, stop in route.stops {
    for right in 0.. instance.capacity(route.vehicle) {
    return Some("capacity-exceeded")
  }
  let arrivals = route_arrivals(instance, route)
  for index, stop in route.stops {
    if arrivals[index] > instance.points[stop].due {
      return Some("time-window-exceeded")
    }
  }
  None
}

///|
/// Validate that every customer appears exactly once.
pub fn validate_plan(
  instance : RoutingInstance,
  plan : RoutingPlan,
) -> Array[String] {
  let errors : Array[String] = []
  if plan.routes.length() != instance.vehicles {
    errors.push("vehicle-count-mismatch")
  }
  let seen : Array[Int] = []
  for route in plan.routes {
    match validate_route(instance, route) {
      Some(error) => errors.push("vehicle_\{route.vehicle}:\{error}")
      None => ()
    }
    for stop in route.stops {
      if seen.contains(stop) {
        errors.push("duplicate-stop-global")
      } else {
        seen.push(stop)
      }
    }
  }
  for customer in instance.customers() {
    if !seen.contains(customer) {
      errors.push("missing-stop-\{customer}")
    }
  }
  errors
}

///|
/// Return a plan's total travel distance.
pub fn plan_distance(instance : RoutingInstance, plan : RoutingPlan) -> Int {
  let mut result = 0
  for route in plan.routes {
    result += route_distance(instance, route)
  }
  result
}

///|
/// Return a plan's largest route distance.
pub fn plan_makespan(instance : RoutingInstance, plan : RoutingPlan) -> Int {
  let mut result = 0
  for route in plan.routes {
    let distance = route_distance(instance, route) +
      route_service(instance, route)
    if distance > result {
      result = distance
    }
  }
  result
}

///|
/// Return a plan's total load.
pub fn plan_load(instance : RoutingInstance, plan : RoutingPlan) -> Int {
  let mut result = 0
  for route in plan.routes {
    result += route_load(instance, route)
  }
  result
}

///|
/// Return the number of customers served by a plan.
pub fn plan_visit_count(plan : RoutingPlan) -> Int {
  plan.visited().length()
}

///|
/// Pick the nearest feasible unserved customer.
fn nearest_feasible(
  instance : RoutingInstance,
  current : Int,
  vehicle : Int,
  route : VehicleRoute,
  remaining : Array[Int],
) -> Int? {
  let mut selected : Int? = None
  let mut selected_distance = 2147483647
  let current_load = route_load(instance, route)
  for candidate in remaining {
    let point = instance.points[candidate]
    if current_load + point.demand <= instance.capacity(vehicle) {
      let distance = instance.distance(current, candidate)
      let better_tie = match selected {
        Some(value) => candidate < value
        None => true
      }
      if distance < selected_distance ||
        (distance == selected_distance && better_tie) {
        selected = Some(candidate)
        selected_distance = distance
      }
    }
  }
  selected
}

///|
/// Remove the first matching integer from an array.
fn remove_first_value(values : Array[Int], target : Int) -> Bool {
  let mut index = 0
  while index < values.length() {
    if values[index] == target {
      while index + 1 < values.length() {
        values[index] = values[index + 1]
        index += 1
      }
      ignore(values.pop())
      return true
    }
    index += 1
  }
  false
}

///|
/// Construct a deterministic nearest-neighbor seed plan.
pub fn nearest_neighbor_plan(instance : RoutingInstance) -> RoutingPlan {
  let plan = routing_plan(instance.vehicles)
  let remaining = instance.customers()
  for vehicle in 0.. {
          ignore(remove_first_value(remaining, stop))
          ignore(plan.append(vehicle, stop))
          current = stop
        }
        None => searching = false
      }
    }
  }
  plan
}

///|
/// Move one customer from an overloaded route to the best insertion point.
pub fn repair_capacity(instance : RoutingInstance, plan : RoutingPlan) -> Int {
  let mut moved = 0
  for source in 0.. instance.capacity(source) {
      if plan.routes[source].stops.length() == 0 {
        break
      }
      let stop = plan.routes[source].stops[plan.routes[source].stops.length() -
        1]
      let mut target : Int? = None
      for vehicle in 0.. {
          ignore(plan.routes[source].stops.pop())
          ignore(plan.append(vehicle, stop))
          moved += 1
        }
        None => break
      }
    }
  }
  moved
}

///|
/// Apply the first improving 2-opt reversal found across all routes.
pub fn improve_two_opt(instance : RoutingInstance, plan : RoutingPlan) -> Int {
  let mut improvements = 0
  let mut changed = true
  while changed {
    changed = false
    for route in plan.routes {
      if route.stops.length() < 3 {
        continue
      }
      let current_distance = route_distance(instance, route)
      for left in 0..= route.stops.length() {
            instance.depot
          } else {
            route.stops[right + 1]
          }
          let old_edges = instance.distance(first, second) +
            instance.distance(third, fourth)
          let new_edges = instance.distance(first, third) +
            instance.distance(second, fourth)
          if new_edges < old_edges && new_edges < current_distance {
            ignore(route.reverse_segment(left, right))
            improvements += 1
            changed = true
            break
          }
        }
        if changed {
          break
        }
      }
      if changed {
        break
      }
    }
  }
  improvements
}

///|
/// Return a plan with customers ordered by descending demand.
pub fn demand_first_plan(instance : RoutingInstance) -> RoutingPlan {
  let plan = routing_plan(instance.vehicles)
  let remaining = instance.customers()
  for left in 0..
        instance.points[remaining[left]].demand {
        let temporary = remaining[left]
        remaining[left] = remaining[right]
        remaining[right] = temporary
      }
    }
  }
  for stop in remaining {
    let mut chosen : Int? = None
    let mut best_slack = 2147483647
    for vehicle in 0..= instance.points[stop].demand && slack < best_slack {
        chosen = Some(vehicle)
        best_slack = slack
      }
    }
    match chosen {
      Some(vehicle) => ignore(plan.append(vehicle, stop))
      None => ()
    }
  }
  plan
}

///|
/// A scalar score useful for comparing heuristic plans.
pub fn routing_score(instance : RoutingInstance, plan : RoutingPlan) -> Int {
  let errors = validate_plan(instance, plan)
  plan_distance(instance, plan) +
  errors.length() * 1000000 +
  plan_makespan(instance, plan)
}

///|
/// Compact quality report for a routing plan.
pub struct RoutingReport {
  distance : Int
  makespan : Int
  load : Int
  visits : Int
  errors : Array[String]
}

///|
/// Produce a report without mutating the plan.
pub fn routing_report(
  instance : RoutingInstance,
  plan : RoutingPlan,
) -> RoutingReport {
  {
    distance: plan_distance(instance, plan),
    makespan: plan_makespan(instance, plan),
    load: plan_load(instance, plan),
    visits: plan_visit_count(plan),
    errors: validate_plan(instance, plan),
  }
}

///|
/// Return whether a report is feasible.
pub fn RoutingReport::feasible(self : RoutingReport) -> Bool {
  self.errors.length() == 0
}

///|
/// Read the travel distance.
pub fn RoutingReport::distance(self : RoutingReport) -> Int {
  self.distance
}

///|
/// Read the route makespan.
pub fn RoutingReport::makespan(self : RoutingReport) -> Int {
  self.makespan
}

///|
/// Read the served load.
pub fn RoutingReport::load(self : RoutingReport) -> Int {
  self.load
}

///|
/// Read the visit count.
pub fn RoutingReport::visits(self : RoutingReport) -> Int {
  self.visits
}

///|
/// Return a stable summary string.
pub fn RoutingReport::describe(self : RoutingReport) -> String {
  "distance=\{self.distance}, makespan=\{self.makespan}, load=\{self.load}, visits=\{self.visits}, errors=\{self.errors.length()}"
}

///|
/// Return the absolute value of an integer.
fn abs_int(value : Int) -> Int {
  if value < 0 {
    -value
  } else {
    value
  }
}

///|
/// Return an integer route signature for caching and regression tests.
pub fn routing_signature(instance : RoutingInstance, plan : RoutingPlan) -> Int {
  let mut signature = 17
  for route in plan.routes {
    signature = signature * 31 + route.vehicle
    for stop in route.stops {
      signature = signature * 31 +
        stop +
        instance.distance(instance.depot, stop)
    }
  }
  signature
}

///|
/// Return a route's cumulative arrival slack values.
pub fn route_slacks(
  instance : RoutingInstance,
  route : VehicleRoute,
) -> Array[Int] {
  let arrivals = route_arrivals(instance, route)
  let result : Array[Int] = []
  for index, stop in route.stops {
    result.push(instance.points[stop].due - arrivals[index])
  }
  result
}

///|
/// Return the first route position violating a time window.
pub fn first_late_stop(
  instance : RoutingInstance,
  route : VehicleRoute,
) -> Int? {
  let arrivals = route_arrivals(instance, route)
  for index, stop in route.stops {
    if arrivals[index] > instance.points[stop].due {
      return Some(stop)
    }
  }
  None
}

///|
/// Return the largest capacity residual among routes.
pub fn capacity_slack(instance : RoutingInstance, plan : RoutingPlan) -> Int {
  let mut result = 0
  for route in plan.routes {
    let slack = instance.capacity(route.vehicle) - route_load(instance, route)
    if slack > result {
      result = slack
    }
  }
  result
}

///|
/// Return the smallest non-negative capacity residual, or -1 when infeasible.
pub fn minimum_capacity_slack(
  instance : RoutingInstance,
  plan : RoutingPlan,
) -> Int {
  let mut result = 2147483647
  for route in plan.routes {
    let slack = instance.capacity(route.vehicle) - route_load(instance, route)
    if slack < 0 {
      return slack
    }
    if slack < result {
      result = slack
    }
  }
  if result == 2147483647 {
    0
  } else {
    result
  }
}

///|
/// Create a linearly spaced point set for deterministic examples.
pub fn grid_routing_points(width : Int, height : Int) -> Array[RoutingPoint] {
  let result : Array[RoutingPoint] = []
  if width <= 0 || height <= 0 {
    return result
  }
  let mut id = 0
  for y in 0.. Array[Array[Int]] {
  plan.routes.map(route => route.stops.copy())
}

///|
/// Return whether a route uses every stop in strictly increasing order.
pub fn is_monotone_route(route : VehicleRoute) -> Bool {
  for index in 1.. Int {
  let mut result = 0
  for left in 0..= route.stops.length() {
        instance.depot
      } else {
        route.stops[right + 1]
      }
      let first = instance.distance(a, b) + instance.distance(c, d)
      let second = instance.distance(a, c) + instance.distance(b, d)
      if second < first {
        result += 1
      }
    }
  }
  result
}

///|
/// Return a route-level objective combining distance, lateness, and crossings.
pub fn route_objective(instance : RoutingInstance, route : VehicleRoute) -> Int {
  let mut lateness = 0
  let arrivals = route_arrivals(instance, route)
  for index, stop in route.stops {
    let late = arrivals[index] - instance.points[stop].due
    if late > 0 {
      lateness += late
    }
  }
  route_distance(instance, route) +
  route_service(instance, route) +
  lateness * 1000 +
  route_crossings(instance, route) * 10
}

///|
/// Return a plan-level objective with deterministic penalties.
pub fn plan_objective(instance : RoutingInstance, plan : RoutingPlan) -> Int {
  let mut result = 0
  for route in plan.routes {
    result += route_objective(instance, route)
  }
  result + validate_plan(instance, plan).length() * 1000000
}

///|
/// Return a compact CSV row for a route.
pub fn route_csv(route : VehicleRoute) -> String {
  let builder = StringBuilder()
  builder.write_string("\{route.vehicle}")
  for stop in route.stops {
    builder.write_string(",\{stop}")
  }
  builder.to_string()
}

///|
/// Render all routes as CSV rows.
pub fn plan_csv(plan : RoutingPlan) -> String {
  let builder = StringBuilder()
  for index, route in plan.routes {
    if index > 0 {
      builder.write_char('\n')
    }
    builder.write_string(route_csv(route))
  }
  builder.to_string()
}

///|
/// Return a plan created by assigning each customer round-robin.
pub fn round_robin_plan(instance : RoutingInstance) -> RoutingPlan {
  let plan = routing_plan(instance.vehicles)
  let mut vehicle = 0
  for stop in instance.customers() {
    ignore(plan.append(vehicle, stop))
    vehicle = (vehicle + 1) % instance.vehicles
  }
  plan
}

///|
/// Return the most distant customer from the depot.
pub fn farthest_customer(instance : RoutingInstance) -> Int? {
  let mut result : Int? = None
  let mut distance = -1
  for customer in instance.customers() {
    let current = instance.distance(instance.depot, customer)
    if current > distance {
      result = Some(customer)
      distance = current
    }
  }
  result
}

///|
/// Return customers sorted by distance from the depot.
pub fn customers_by_depot_distance(instance : RoutingInstance) -> Array[Int] {
  let result = instance.customers()
  for left in 0.. Int {
  let mut result = 0
  for customer in instance.customers() {
    if plan.locate(customer) is None {
      result += 1
    }
  }
  result
}

///|
/// Return whether every route has a distinct vehicle identifier.
pub fn distinct_route_vehicles(plan : RoutingPlan) -> Bool {
  for left, route in plan.routes {
    for right in 0.. Int {
  if plan.routes.length() == 0 {
    return 0
  }
  plan_distance(instance, plan) / plan.routes.length()
}

///|
/// Return the average customer demand using integer division.
pub fn average_customer_demand(instance : RoutingInstance) -> Int {
  let customers = instance.customers()
  if customers.length() == 0 {
    return 0
  }
  instance.total_demand() / customers.length()
}

///|
/// Return whether every point identifier matches its array position.
pub fn routing_ids_are_dense(instance : RoutingInstance) -> Bool {
  for index, point in instance.points {
    if point.id != index {
      return false
    }
  }
  true
}