Dial a Ride Problem(DARP)基于Gurobi优化的大规模节点/边数据预处理与计算效率提升方案问询
优化DARP模型在Gurobi中的求解速度:针对非连通节点对的预处理方案
我完全懂你现在的困扰——用全节点对矩阵建模大规模路网的DARP,单个请求就要跑1小时,核心问题就是那些大量非连通节点对带来的冗余变量和计算开销。下面我分享几个针对Gurobi的高效优化技巧,帮你把计算时间压下来:
1. 只给实际存在的边创建决策变量
别再维护338×338的全量x[i,j]矩阵了!直接基于OSMnx导入的826条有效边来定义变量,这能把决策变量的数量从11万+直接砍到800多,效果立竿见影:
# 从OSMnx图中提取所有实际连通的节点对 valid_edges = [(u, v) for u, v, _ in graph.edges(data=True)] # 仅为有效边创建Gurobi二元变量 x = m.addVars(valid_edges, vtype=GRB.BINARY, name="x")
2. 重构约束,只遍历邻接边
之前的约束(比如流守恒)可能是遍历所有节点对的,现在改成只处理每个节点的邻接边就行。Gurobi的sum方法能高效处理这种邻接求和:
for node in graph.nodes(): # 计算流入该节点的总流量 inflow = x.sum('*', node) # 计算流出该节点的总流量 outflow = x.sum(node, '*') # 替换成你的DARP流守恒规则(比如起点流出+1、终点流入+1等) m.addConstr(inflow - outflow == node_demand[node], name=f"flow_conserv_{node}")
3. 开启Gurobi的强预处理参数
就算做了变量裁剪,还能通过调整Gurobi参数让预处理更给力:
Presolve=2:启用最强预处理,自动移除冗余约束和变量PreCrush=1:把模型预处理后转换成更紧凑的形式Heuristics=0.5:增加启发式算法的时间占比,更快找到可行解
设置方式很简单:
m.setParam('Presolve', 2) m.setParam('PreCrush', 1) m.setParam('Heuristics', 0.5)
4. 提前计算可达节点对的最短路径(如果需要路径成本)
如果你的模型需要用到节点间的最短路径成本,别用大数填充的全矩阵,直接用OSMnx计算仅可达的节点对路径长度:
import osmnx as ox # 计算所有可达节点对的最短路径长度(按边的length权重) sp_lengths = ox.shortest_path_length(graph, weight='length') # 把结果整理成只包含可达节点对的字典 valid_shortest_paths = {} for u in sp_lengths: for v, length in sp_lengths[u].items(): valid_shortest_paths[(u, v)] = length
之后在模型里引用成本时,只查这个字典里的键值对,彻底避开非连通节点对的处理。
5. 可选:尝试用路径变量替代边变量
如果是单车辆或少量车辆的DARP场景,你可以考虑直接定义路径变量(比如y[k]表示选择第k条可行路径),而不是边变量。这种方式能简化约束,但变量规模会随可行路径数增加而变大,适合场景相对简单的情况。
这些方法组合起来,应该能把单个请求的计算时间从小时级压缩到分钟甚至更短。优先从裁剪决策变量开始,这是最直接有效的优化步骤。
内容的提问来源于stack exchange,提问作者Pim Hofste
相关产品推荐
相关产品推荐

