首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Ortools VRP错误时,试图合并处罚和不同的起点-终点仓库

Ortools VRP错误时,试图合并处罚和不同的起点-终点仓库
EN

Stack Overflow用户
提问于 2022-02-07 10:53:16
回答 2查看 192关注 0票数 2

我试图解决一个VRP问题,允许通过惩罚和多个仓库丢弃节点。

守则适用于罚款及车辆在同一车场起止的情况:

代码语言:javascript
运行
复制
    data['num_vehicles'] = 2
    data['start'] = [0, 4]
    data['end'] = [0, 4]

代码可以很好地处理在不同车库开始和结束的车辆,并将for循环注释到AddDisjunction以进行惩罚(不允许丢弃节点):

代码语言:javascript
运行
复制
    data['num_vehicles'] = 2
    data['start'] = [0, 4]
    data['end'] = [0, 9]
    .........................
    #for node in range(1, len(data['penalties'])):
    #     routing.AddDisjunction([manager.NodeToIndex(node)], data['penalties'][node])

但是,当车辆在不同的车库开始和结束,并试图增加惩罚,以允许丢弃节点,python与错误崩溃(调试,我可以看到,在添加不同终端仓库的惩罚失败):

F00-1:-1:-1.000244 24944 routing.cc:1622]检查失败: kUnassigned !=索引i

我找不到关于这个错误的任何参考资料。我查看了第1622行的routing.cc源代码,但是我看不到与错误有任何关系。我需要帮助来解决这个问题。

下面是源代码:

代码语言:javascript
运行
复制
from ortools.constraint_solver import routing_enums_pb2
from ortools.constraint_solver import pywrapcp


def create_data_model():
    """Stores the data for the problem."""
    data = {}
    data['distance_matrix'] = [
        [0, 2253, 2479, 2792, 4707, 6128, 1567, 5643, 1234, 3345, 1827], 
        [1731, 0, 2193, 2507, 3624, 5040, 3467, 2921, 5791, 1546, 2345], 
        [1867, 2112, 0, 676, 4406, 5824, 988, 4567, 2134, 4453, 2123], 
        [2339, 2585, 893, 0, 4879, 6302, 1543, 1298, 6890, 1456, 5623], 
        [4464, 3766, 5935, 4957, 0, 1749, 987, 3212, 3451, 5212, 3321], 
        [6568, 5862, 8023, 7055, 2148, 0, 4567, 2124, 4321, 3212, 1234],
        [731, 2193, 2507, 7624, 4040, 4467, 0, 2621, 3791, 1567, 1345],
        [1731, 3193, 1507, 3624, 6040, 2467, 4921, 0, 5791, 6723, 1345],
        [2731, 3193, 2507, 6204, 5040, 1467, 2210, 6791, 0, 2567, 6421],
        [3345, 1543, 4421, 1531, 5213, 3215, 1512, 6213, 2431, 0, 5673],
        [1832, 2421, 2144, 5232, 3214, 1234, 1432, 1231, 6321, 5461, 0],
        ]
    data['node_time'] = [0, 7200, 3600, 5400, 0, 5400, 7200, 3600, 7200, 0, 300]
    data['num_vehicles'] = 2
    data['start'] = [0, 4]
    data['end'] = [0, 9]
    # Penalizaciones por no visitar nodos (drop nodes) en caso de que no tenga solución:
    # MAXINT 0x7FFFFFFFFFFFFFF: Hace obligatoria la visita al nodo, no se puede eliminar de la solución
    # 1000000: Se puede no visitar el nodo con penalización. La penalización debe ser grande, mayor que 10x veces el mayor tiempo de visita, para evitar que salga mas rentable dejar caer el nodo que pagar la penalización
    # 0: En los nodos "depósito" de vehículos, no son visitas intermedias sino inicio y fin de la ruta.
    data['penalties'] = [0, 1000000, 1000000, 1000000, 0, 0x7FFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFF, 1000000, 1000000, 0, 1000000]
    return data


def print_solution(data, manager, routing, solution):
    """Prints solution on console."""
    print(f'Objective: {solution.ObjectiveValue()}')

    # Display dropped nodes.
    dropped_nodes = 'Nodos sin visitar:'
    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 + '\n')

    max_route_distance = 0
    for vehicle_id in range(data['num_vehicles']):
        index = routing.Start(vehicle_id)
        plan_output = 'Ruta para vehículo {}:\n'.format(vehicle_id)
        route_distance = 0
        while not routing.IsEnd(index):
            plan_output += ' {} -> '.format(manager.IndexToNode(index))
            previous_index = index
            index = solution.Value(routing.NextVar(index))
            route_distance += routing.GetArcCostForVehicle(
                previous_index, index, vehicle_id)
        plan_output += '{}\n'.format(manager.IndexToNode(index))
        plan_output += 'Tiempo de la ruta: {}sg\n'.format(route_distance)
        print(plan_output)
        max_route_distance = max(route_distance, max_route_distance)
    print('Maximo tiempo de las rutas: {}sg'.format(max_route_distance))



def main():
    """Entry point of the program."""
    # Instantiate the data problem.
    data = create_data_model()

    # Create the routing index manager.
    manager = pywrapcp.RoutingIndexManager(len(data['distance_matrix']),
                                           data['num_vehicles'], data['start'], data['end'])

    # Create Routing Model.
    routing = pywrapcp.RoutingModel(manager)


    # Create and register a transit callback.
    def distance_callback(from_index, to_index):
        """Returns the distance between the two nodes."""
        # Convert from routing variable Index to distance matrix NodeIndex.
        from_node = manager.IndexToNode(from_index)
        to_node = manager.IndexToNode(to_index)
        tiempo_desplazamiento = data['distance_matrix'][from_node][to_node]
        tiempo_ejecucion = data['node_time'][to_node]
        return tiempo_desplazamiento + tiempo_ejecucion

    transit_callback_index = routing.RegisterTransitCallback(distance_callback)

    # Define cost of each arc.
    routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)

    # Add Distance constraint.
    routing.AddDimension(
        transit_callback_index,
        0,  # no slack
        27000,  # vehicle maximum travel distance (7.5 hours, in seconds)
        True,  # start cumul to zero
        'Time')
    distance_dimension = routing.GetDimensionOrDie('Time')
    distance_dimension.SetGlobalSpanCostCoefficient(100)

    # Allow to drop nodes.
    for node in range(1, len(data['penalties'])):
        routing.AddDisjunction([manager.NodeToIndex(node)], data['penalties'][node])

    # Setting first solution heuristic.
    search_parameters = pywrapcp.DefaultRoutingSearchParameters()
    search_parameters.first_solution_strategy = (routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)
    search_parameters.local_search_metaheuristic = (routing_enums_pb2.LocalSearchMetaheuristic.GUIDED_LOCAL_SEARCH)
    search_parameters.time_limit.seconds = 30

    # Solve the problem.
    solution = routing.SolveWithParameters(search_parameters)

    # Print solution on console.
    if solution:
        print_solution(data, manager, routing, solution)
    else:
        print('No solution found!')


if __name__ == '__main__':
    main()

我在Ortools Google上发布了这个问题,还有更多的研究: https://groups.google.com/g/or-tools-discuss/c/s3PfgLVZpj0

正如在那篇文章中所解释的,代码似乎在将开始和结束节点排除在分离之外,但是我想要更多的信息来理解它是如何工作的。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-02-15 10:14:46

在routing.h中有一个关于AddDisjunction的评论

代码语言:javascript
运行
复制
/// Adds a disjunction constraint on the indices: exactly 'max_cardinality' of
/// the indices are active. Start and end indices of any vehicle cannot be
/// part of a disjunction.

在for循环中,要将节点添加到分离,不包括开始节点和结束节点似乎是有效的:

代码语言:javascript
运行
复制
  # Allow to drop nodes.
  for node in range(0, len(data['distance_matrix'])):
    if(node in data['start'] or node in data['end']):
        continue
    else:
        routing.AddDisjunction([manager.NodeToIndex(node)], data['penalties'][node])
票数 0
EN

Stack Overflow用户

发布于 2022-02-07 10:59:34

对于定制的开始和结束,您应该使用Routing.Start(vehicle_index)Routing.End(vehicle_index)来获取这些节点的索引。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71017337

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档