Python中Pulp变量出现NoneType与int比较错误的求助
TSP求解变量值为None的问题分析与解决
问题描述
使用Python结合Pulp库求解旅行商问题(TSP),循环处理不同规模的TSP文件时,前3个小文件运行正常,但处理第4个及更大规模文件时,print_prob函数中执行v.varValue >= 1时触发错误:'>=' not supported between instances of 'NoneType' and 'int',即变量的varValue属性为None。需明确问题原因并给出解决建议。
相关代码
触发错误的print_prob函数
def print_prob(prob, timelimit): for v in prob.variables(): if (v.varValue >= 1): print(v.name, "=", v.varValue) print(value(prob.objective)) if timelimit >= 0: print("剩余执行时间:", timelimit) print("总执行时间:", max_time - timelimit) else: print("在给定时间内未找到最优解。") #print(prob) return
全局处理逻辑
def testing_all_3(i): # 文件名列表 file = ['wi29', 'dj38', 'qa194', 'uy734', 'zi929', 'lu980', 'rw1621', 'mu1979', 'nu3496', 'ca4663'] print("===============") print("测试文件", file[i] + ".tsp") # 使用专用函数打开TSP文件(TSP格式有对应的处理库) bench = _tspfile(file[i] + ".tsp") n = bench.dimension # 根据文件数据生成节点列表(用数字表示) cidades, destinos = _append(n) # 将节点权重转换为Pulp可用的字典格式 costs = _tsp(n, bench) costs = makeDict([cidades, destinos], costs, 0) # 调用两个类似的求解函数 print("使用MTZ方法求解") solvingMTZ(cidades, destinos, n, costs, file[i]) print("===============") print("测试文件", file[i] + ".tsp") print("使用DL方法求解") solvingDL(cidades, destinos, n, costs, file[i]) for i in range(5,10): # 原本会遍历0到9,但第4个及之后的文件才会报错 testing_all_3(i)
核心MTZ求解函数
def solvingMTZ(cidades, destinos, n, costs, file): prob = LpProblem("Teste", LpMinimize) road = [(cid_i, cid_j) for cid_i in cidades for cid_j in destinos] var = LpVariable.dicts("Road", (cidades, destinos), 0, 1, LpInteger) # 目标函数 prob += lpSum([var[cid_i][cid_j] * costs[cid_i][cid_j] for (cid_i, cid_j) in road]) # 约束:每个节点仅出一次 for i in cidades: prob += lpSum([var[i][cid_j] for cid_j in destinos if i != cid_j]) == 1 # 约束:每个节点仅入一次 for j in destinos: prob += lpSum([var[cid_i][j] for cid_i in cidades if j != cid_i]) == 1 prob = mtz(n, prob, cidades, var) timelimit = max_time start = time.time() prob.solve(GUROBI_CMD(timeLimit=timelimit, msg=1, gapRel=0)) end = time.time() timelimit = timelimit - end + start print(timelimit) # 打印变量值和最终结果 print_prob(prob, timelimit) make_node_fileMTZ(prob, file, timelimit) return # MTZ约束生成函数(DL方法的求解函数几乎完全相同,此处省略) def mtz(n, prob, cidades, var): u = LpVariable.dicts('u', (i for i in cidades), 1, n-1, LpInteger) for i in cidades[1:]: for j in cidades[1:]: # if i != j: prob += u[i] - u[j] + (n - 1) * var[i][j] <= n - 2 return prob
问题原因
- 求解超时无可行解:大规模TSP的变量数和约束数随节点数呈指数增长,当前设置的
timeLimit不足以让Gurobi找到可行解。小问题求解速度快,能在时限内完成,变量有有效值;大问题超时后,求解器未返回任何可行解,变量varValue保持为None。 - 未检查求解状态:代码直接访问变量值,未判断求解是否成功。Pulp中
prob.solve()返回状态码,超时情况下状态通常为LpStatusNotSolved或LpStatusTimeLimit,此时变量无有效值。 - MTZ约束效率低下:MTZ约束数量为O(n²),节点数增大后约束暴增,不仅减慢求解速度,还可能导致求解器在时限内无法找到可行解,甚至引发数值稳定性问题。
解决建议
1. 先检查求解状态再访问变量
在print_prob中先判断求解状态,仅当有可行解时才遍历变量:
def print_prob(prob, timelimit): status = LpStatus[prob.status] # 仅处理最优或可行状态 if status not in ["Optimal", "Feasible"]: print(f"求解状态:{status},无有效变量值") obj_val = value(prob.objective) if prob.objective else "N/A" print(f"目标函数值:{obj_val}") if timelimit < 0: print("在给定时间内未找到最优解。") else: print("剩余执行时间:", timelimit) print("总执行时间:", max_time - timelimit) return # 遍历变量时增加None判断 for v in prob.variables(): if v.varValue is not None and v.varValue >= 1: print(v.name, "=", v.varValue) print("目标函数值:", value(prob.objective)) # 时间打印逻辑 if timelimit >= 0: print("剩余执行时间:", timelimit) print("总执行时间:", max_time - timelimit) else: print("在给定时间内未找到最优解。")
2. 调整求解器参数
- 增大
timeLimit,给大规模问题足够的求解时间; - 放宽
gapRel参数(如设为0.05),允许求解器在找到接近最优的可行解时提前终止,避免超时无结果; - 开启多线程加速,如
GUROBI_CMD(timeLimit=timelimit, msg=1, gapRel=0.05, threads=4)。
3. 优化TSP模型
MTZ模型不适用于大规模TSP(n>500),建议:
- 使用Gurobi内置的TSP求解接口(更高效,针对TSP做了优化);
- 改用启发式算法(如遗传算法、模拟退火)快速得到可行解,再结合整数规划做局部优化;
- 选择更高效的整数规划模型(如基于子回路消除的分支定界模型)。
4. 变量访问时增加None判断
即使求解状态正常,个别变量可能因数值问题未赋值,因此必须先判断v.varValue is not None再做比较。
内容的提问来源于stack exchange,提问作者Gabriel Sanches da Silva
相关产品推荐
相关产品推荐

