每次交货多次取货时,无法找到部分解决方案

问题描述

使用OR工具,我试图为每个交付的多个取货问题建模,并提出分离,即只有当所有取货都在交付到达之前就已固化,并且无法让求解器找到部分解决方案时,才可以实现交付。 在下面的玩具示例中,求解器可以在给定的MAX_ROUTE_TIME限制内完成前两个拾取及其交付时返回空解决方案。我是否正确设置每次交付的多功能取纸器?

我尝试了以下方法,但未成功:

  1. 添加一个约束,要求将相同交付的皮卡分配给同一辆车。
  2. 将交付节点分成2个,将提取和交付设置为每对提取-交付,并设置相同的车辆约束和相同的累积值。
  3. 将取件的罚款设为0,而将交货的罚款设为相同。
import numpy as np
from ortools.constraint_solver import routing_enums_pb2,pywrapcp


manager = pywrapcp.RoutingIndexManager(7,1,0)
routing = pywrapcp.RoutingModel(manager)
dim_name = 'Time'
durations = np.array(
  [[  0,100,100],[  1,[100,0]])

def duration_callback(from_index,to_index):
        from_node = manager.IndexToNode(from_index)
        to_node = manager.IndexToNode(to_index)
        return durations[from_node][to_node]
    
transit_callback_index = routing.RegisterTransitCallback(duration_callback)
routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)
MAX_ROUTE_TIME = 400
routing.AddDimension(transit_callback_index,MAX_ROUTE_TIME,True,dim_name)
time_dimension = routing.GetDimensionorDie(dim_name)

pickups_deliveries = [
    (1,3),(2,(4,6),(5,6)
]

for pickup,delivery in pickups_deliveries:
    pickup_index = manager.NodetoIndex(pickup)
    delivery_index = manager.NodetoIndex(delivery)
    routing.AddPickupAndDelivery(pickup_index,delivery_index)
    routing.solver().Add(routing.VehicleVar(pickup_index) == routing.VehicleVar(delivery_index))
    routing.solver().Add(time_dimension.CumulVar(pickup_index) <= time_dimension.CumulVar(delivery_index))

for node in range(1,7):
    routing.Adddisjunction([manager.NodetoIndex(node)],10000000)

search_parameters = pywrapcp.DefaultRoutingSearchParameters()
search_parameters.first_solution_strategy = routing_enums_pb2.FirstSolutionStrategy.AUTOMATIC
search_parameters.local_search_Metaheuristic = routing_enums_pb2.LocalSearchMetaheuristic.GUIDED_LOCAL_SEARCH
search_parameters.lns_time_limit.seconds = 2
search_parameters.time_limit.seconds = 5
solution = routing.solveWithParameters(search_parameters)

vehicle_id = 0
index = routing.Start(vehicle_id)
node = manager.IndexToNode(index)
while not routing.IsEnd(index):
    prevIoUs_node = node
    prevIoUs_index = index
    index = solution.Value(routing.Nextvar(index))
    node = manager.IndexToNode(index)
    print(prevIoUs_node,node,durations[prevIoUs_node,node])

解决方法

您必须复制节点// Register your collectors elapsed := prometheus.NewGaugeVec(prometheus.GaugeOpts{ Name: "gogrinder_elapsed_ms",Help: "Current time elapsed of gogrinder teststep",},[]string{"teststep","user","iteration","timestamp"}) prometheus.MustRegister(elapsed) // Remove Go collector prometheus.Unregister(prometheus.NewGoCollector()) 3,即该节点不能属于两个不同的P&D ...

非常丑陋的修复(我使用了Python 3.6+ f字符串语法(^ v ^)):

6

可能的输出:

...
manager = pywrapcp.RoutingIndexManager(7+2,1,0)
...
def duration_callback(from_index,to_index):
        from_node = manager.IndexToNode(from_index)
        if from_node == 7:
            from_node = 3
        if from_node == 8:
            from_node = 6
        to_node = manager.IndexToNode(to_index)
        if to_node == 7:
            to_node = 3
        if to_node == 8:
            to_node = 6
        return durations[from_node][to_node]

...
for node in range(1,9):
    routing.AddDisjunction([manager.NodeToIndex(node)],10000000)
...

print(f"objective: {solution.ObjectiveValue()}")

# Display dropped nodes.
dropped_nodes = 'Dropped nodes:'
for node in range(routing.Size()):
    if routing.IsStart(node) or routing.IsEnd(node):
        continue
    if solution.Value(routing.NextVar(node)) == node:
        dropped_nodes += ' {}'.format(manager.IndexToNode(node))
print(dropped_nodes)

vehicle_id = 0
index = routing.Start(vehicle_id)
node = manager.IndexToNode(index)
while not routing.IsEnd(index):
    previous_node = node
    pmap = previous_node
    if pmap == 7:
        pmap = 3
    if pmap == 8:
        pmap = 6
    previous_index = index
    index = solution.Value(routing.NextVar(index))
    node = manager.IndexToNode(index)
    nmap = node
    if nmap == 7:
        nmap = 3
    if nmap == 8:
        nmap = 6
    print(f"{previous_node} -> {node} ({durations[pmap,nmap]})")
,

在这种情况下,我想放弃整个交货

在这种情况下,可以在每个节点[1,2,3][4,5,6]上使用一个析取,而不是每个节点使用一个析取。

routing.AddDisjunction([manager.NodeToIndex(i) for i in (1,3,7)],10000000,4)
routing.AddDisjunction([manager.NodeToIndex(i) for i in (4,6,8)],4)

#for node in range(1,9):
#    routing.AddDisjunction([manager.NodeToIndex(node)],10000000)

ref:https://github.com/google/or-tools/blob/a0a56698ba8fd07b7f84aee4fc45d891a8cd9828/ortools/constraint_solver/routing.h#L570-L588

可能的输出:

[127]─[~/work/tmp/issue]
[>_<]─mizux@nuc10i7 %./so_2020_09_06_2.py
objective: 10000004
Dropped nodes: 4 5 6 8
0 -> 2 (1)
2 -> 1 (1)
1 -> 7 (1)
7 -> 3 (0)
3 -> 0 (1)
[0]─[~/work/tmp/issue]
[^v^]─mizux@nuc10i7 %