Оптапланер - CVRP - возвращение на склад в середине поездки

Моя проблема - это модификация CVRP, которая в конечном итоге будет также включать временные окна. Поскольку временные окна уже встроены в примеры, мне не должно быть слишком сложно их понять. Однако мне нужно изменить одно из основных ограничений примеров CVRP, и я немного растерялся, как это сделать.

В системе, которую я пытаюсь смоделировать, автомобиль может покинуть свой склад, перейти к нескольким различным клиентам и загрузить материал. Однако, где моя модель отличается от примеров, это то, что Транспортное средство может посетить любую среднюю цепь Депо, чтобы разместить свою текущую нагрузку.

Я просматривал документацию, пытаясь выяснить, как это сделать, и мое базовое понимание до сих пор состоит в том, что мне придется изменить определение Depot (возможно, путем внедрения Standstill), чтобы иметь возможность быть частью цепочки мест, где автомобиль посещает, и / или, возможно, просто интегрирует Депо в Заказчика с каким-то особым правилом, согласно которому посещение Депо освобождает автомобиль, а не увеличивает спрос. Я также смотрел на теневые переменные и слушатели переменных, но я не знаю, правильно ли это сделать. Это все немного сбивает с толку.

Может кто-нибудь дать несколько советов или советов, или указать мне правильное направление, с чего начать, прежде чем я слишком глубоко закопаюсь в яму?

0 ответов

Основываясь на предложении Джеффри, переименуйте свой Vehicle класс к VehicleTripи пусть он указывает на предыдущую и следующую поездку, присвоив ему значениеpreviousVehicleTrip а также nextVehicleTrip, и задайте ему переменное время начала и время окончания (примеры кода на Kotlin):

class VehicleTrip(
    ...,
    var startTime: LocalDateTime? = null,
    var endTime: LocalDateTime? = null,
    val previousVehicleTrip?: VehicleTrip = null,
    val nextVehicleTrip?: VehicleTrip = null
) : Standstill {
    ...
}

Вы можете установить эти значения при запуске вашего VehicleTrips. Когда вы получитеStackOverFlowError на основе VehicleTrip.hashCode(), просто переопределите hashCode() функция VehicleTripучебный класс. (Может быть, у кого-то есть лучшее предложение для решения этой проблемы?)

Обновление теневых переменных.

В вашем Customer class, у вас должна быть переменная arrivalTime(как в примере CVRPTW), которая является настраиваемой переменной тени. В классе слушателя этой переменной вы обычно обновляете только время прибытия транспортного средства к клиенту и время прибытия клиентов, которые будут следующими в этой поездке. Теперь вам также необходимо обновить все поездки, которые наступают после поездки, в которой находится ваш текущий клиент.

Например, у вас может быть две поездки VT1 а также VT2, и три покупателя C1, C2, а также C3. При переходе с

VT1 - C1 - VT2 - C2 - C3

к

VT1 - C2 - C1 - VT2 - C3

то, что вы хотите обновить, (по порядку)

  1. C2.arrivalTime
  2. C1.arrivalTime
  3. VT1.endTime
  4. VT2.startTime
  5. C3.arrivalTime
  6. VT2.endTime

Обратите внимание, что в TimeWindowedCustomer Например, прослушиватель переменных выполняет только шаги 1 и 2, поэтому мы должны добавлять шаги с 3 по 6.

Для этого начните с добавления @CustomShadowVariable аннотации к времени начала и окончания VehicleTrip (и не забудьте отметить VehicleTrip в качестве объекта планирования), который использует тот же класс слушателя переменных, что и заказчик с временным окном:

class VehicleTrip(
   ...,
   @CustomShadowVariable(
        variableListenerRef = PlanningVariableReference(
            entityClass = TimeWindowedCustomer::class, 
            variableName = "arrivalTime"
        ))
   var startTime: LocalDateTime? = null,
   ...
) : Standstill {
    ...
}

Теперь в ArrivalTimeUpdatingVariableListenerкласса, вы можете добавить шаги с 3. по 6. аналогично тому, как реализованы шаги 1. и 2.. Убедитесь, что вы соблюдаете порядок обновления этих переменных и уведомляетеScoreDirector при изменении переменной с помощью beforeVariableChanged() а также afterVariableChanged() методы.

Другие вопросы по тегам