Оптапланер - 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
то, что вы хотите обновить, (по порядку)
C2.arrivalTime
C1.arrivalTime
VT1.endTime
VT2.startTime
C3.arrivalTime
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()
методы.