python调用cplex解决规划问题(一)

最近开始学习线性规划方面的知识,为今后的工作做准备。拿了一个四城市双向联通的旅行商问题(TSP)练手。

python下调用cplex求解器

  1. 我是用的版本是python3.7和cplex12.9进行优化求解。关于安装cplex包,我采用的是将安装包python文件夹下的cplex文件重构到python项目当中的方法,具体文件可以看下面的图片。
  2. 文件位置
  3. 直接import cplex就行了,我看到网上有很多人用的都是docplex写的,但是我写的时候已经用了cplex包了,所以就用cplex包坚持写下去了。

解决TSP问题的思路

我采用的是算法复杂度更小的MZT模型,还有另一种DFJ模型(记得好像是这个(lll¬ω¬))
下面介绍一下MZT模型的数学原理:
原理部分参考的liuao0910 原创的微信推文,是公众号运筹学分享交流出的文章,网址:https://mp.weixin.qq.com/s?src=11&timestamp=1602920495&ver=2649&signature=WzPYzrNLpCz3VeuGZ-xS2AMLNww5Qy5RXHOmlpkb9ISfR4mdODbqVSDMJ015cSbbM7OOqFYBCh7sV0y9RGLUVTKY7OBqLRkT-4snlEBd9f0*cCBEe7WEg73tawkl5mkb&new=1
下面是一张有向图(图片来源于网络,转侵删):
这是一个有向图
xij代表i城和j城之间的接通关系,等于1就表示走了,等于零就表示没有走这条路。通过x这个0-1变量,再配上代表距离的权重,在保证所有节点都经过且经过一次的条件下,走的距离最小就完事了。前面量个约束条件都是代表流量限制的意思,保证每个节点都经过且只经过一次。后面带有连续变量u的条件是消除子环的。
在这里插入图片描述
在这里插入图片描述
如果不加最后的约束条件有可能子回路就直接满足条件了。
用反证法可以证明:
1)根据上述公式,如果i到j有连边,那么x[i][j]=1,约束就变成:u[i]-u[j]<=-1。也就是,u[j]>=u[i]+1;沿着这个子回路,u[i]是一直增加的;

2)假定存在子回路,满足上述约束。找到一个不包含起点1的子回路,比如,2->4->6->2。那么,就有u[2]>=u[6]+1>=u[4]+2>=u[2]+3这是矛盾的。u[2]不可能大于等于u[2]+3啊,你说对吧!

关于原理的一个坑

大家注意最后一条约束子环的条件,他不是从起点出发的,更进一步说如果在写程序的时候把起点也约束进去,那肯定是不可能找到解的。应该会提示Cplex Error 1217:No solution exists.(好像是这个错来着)。由于个人比较菜,这个错误卡了我一天之久,希望大家避坑吧!

python代码

x变量由于节点少,约束系数矩阵是我手动敲的( ̄y▽ ̄)╭ Ohohoho…。u与x变量混合的约束条件是我用for循环写出来的,我python 和cplex用的都不熟练,大家凑活看吧!我解的大约是这么一张图。
在这里插入图片描述

"""
1.这次解决的是四城市数量的旅行商问题
2.使用线性规划模型
3.调用cplex包 
"""
import cplex

# 将城市节点数量与他们之间的距离表示出来
number = 4
nodes = 3
my_obj = [0, 20, 50, 70, 20, 0, 30, 80, 50, 30, 0, 100, 70, 80, 100, 0, 0, 0, 0, 0]
# 变量的名称
b_var = ["x11", "x12", "x13", "x14", "x21", "x22", "x23", "x24", "x31", "x32", "x33", "x34",
         "x41", "x42", "x43", "x44"]
b_var_ind_format = [["x11", "x12", "x13", "x14"], ["x21", "x22", "x23", "x24"], ["x31", "x32", "x33", "x34"],
                    ["x41", "x42", "x43", "x44"]]
c_var = ["u1", "u2", "u3", "u4"]
my_sense_b = "E" * 12  # 限流变量约束条件类型定义
my_sense_c = "L" * 6  # 连续变量约束条件类型定义
my_rownames_b = ["r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12"]  # 约束条件的名称
my_rownames_c = []
list_c = []  # 存储约束条件中变量和他们系数的小列表
rows_c = []
result = []
# 下面是一个构建连续变量约束条件系数矩阵的循环程序
k = 0
for i in range(1, 4):
    for j in range(1, 4):
        if i != j:
            list_c.append([c_var[i], c_var[j], b_var_ind_format[i][j]])
            # 上面是完成了一个变量的小组合
            list_c.append([1, -1, number])
            rows_c.append([list_c[k], list_c[k + 1]])
            k += 2
rhs_n = len(rows_c)
print(rhs_n)
print("定义连续变量的约束条件为:", rows_c)
# rhs = [float(nodes)] * int(rhs_n)
# print(len(rhs)),这些都是找错误用的
# 下面构建连续约束条件的名字
for i in range(int(rhs_n)):
    my_rownames_c.append("c" + str(i + 1))


def tsp_method(prob):
    """
    :param prob:代表建立起的cplex实例
    :return: 无返回值
    实现变量的添加,设置好约束条件了。针对旅行商问题我们设置的变量为0-1变量,约束条件为MZT模型
    """
    prob.objective.set_sense(prob.objective.sense.minimize)  # 目标函数的意义

    prob.variables.add(names=b_var + c_var, types="B" * 16 + "C" * 4, obj=my_obj)  # 定义变量名,定义0-1类型,定义目标函数系数
    # prob.variables.add(names=c_var, types="C" * 4)  # 定义连续变量,消除子环

    rows = [[["x21", "x31", "x41"], [1.0, 1.0, 1.0]],
            [["x12", "x32", "x42"], [1.0, 1.0, 1.0]],
            [["x13", "x23", "x43"], [1.0, 1.0, 1.0]],
            [["x14", "x24", "x34"], [1.0, 1.0, 1.0]],
            [["x12", "x13", "x14"], [1.0, 1.0, 1.0]],
            [["x21", "x23", "x24"], [1.0, 1.0, 1.0]],
            [["x31", "x32", "x34"], [1.0, 1.0, 1.0]],
            [["x41", "x42", "x43"], [1.0, 1.0, 1.0]],
            [["x11"], [1.0]],
            [["x22"], [1.0]],
            [["x33"], [1.0]],
            [["x44"], [1.0]]]  # 这个是定义限制流量的约束条件的系数
    rhs = [float(nodes)] * int(rhs_n)
    prob.linear_constraints.add(lin_expr=rows + rows_c, senses=my_sense_b + my_sense_c,
                                rhs=[1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0] + rhs,
                                names=my_rownames_b + my_rownames_c)  # 建立好约束条件
    # prob.linear_constraints.add(lin_expr=rows_c, senses=my_sense_c,
    #                             rhs=[float(nodes)] * int(rhs_n),
    #                             names=my_rownames_c)


my_prob = cplex.Cplex()
handle = tsp_method(my_prob)
my_prob.solve()

# except CplexError as exc:
#     print("异常就是这个", exc)
print()
# solution.get_status() returns an integer code
print("Solution status = ", my_prob.solution.get_status(), ":", end='')

# the following line prints the corresponding string
print(my_prob.solution.status[my_prob.solution.get_status()])
# print("Solution value  = ", my_prob.solution.get_objective_value())  # 这个函数是返回目标函数值

numcols = my_prob.variables.get_num()
numrows = my_prob.linear_constraints.get_num()

x = my_prob.solution.get_values()

print("x: ")
print(x)
print('1', end='')
for i in range(len(x)):
    if x[i] == 1 and i < len(x) - 4:  # 因为后面四个变量都是ui所以不把他们作为路径点统计
        print("->", b_var[i][2], end='')

刚接触python和cplex线性规划什么的,如有错误多多包涵。希望能和小伙伴们快乐交流,共同成长!

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值