好久不写博客了,大部分时间都用来干一些重复而繁杂的工作,好久没有认认真真学习一些东西了。
借着参加服创的机会要入手学习一些运筹学知识,就从Cplex开始吧。
首先直接用Python的cplex接口写线性规划比较简单,话不多说直接从实例看:
每一句的详解都在旁边的注释上
Cplex实例
# The MIP problem solved in this example is:
#
# Maximize x1 + 2 x2 + 3 x3 + x4
# Subject to
# - x1 + x2 + x3 + 10 x4 <= 20
# x1 - 3 x2 + x3 <= 30
# x2 - 3.5x4 = 0
# Bounds
# 0 <= x1 <= 40
# 0 <= x2
# 0 <= x3
# 2 <= x4 <= 3
# Integers
# x4
import cplex
from cplex.exceptions import CplexError
# 首先实现定义各参数,包括变量和变量约束等
# 用来在之后方便地添加到优化器里面
# obj 指的是objective 意为目标,
# 也就是要优化的目标(函数x1 + 2 x2 + 3 x3 + x4 的最小值)的系数
my_obj = [1.0, 2.0, 3.0, 1.0]
#ub Upper Bound,上界,分别表示x1,x2,x3,x4的上界,infinity就是无穷大
#(计算机类无穷大是有穷的,所以这个数可以事先修改为一个很大的数如 cplex.infinity = 2147483647
my_ub = [40.0, cplex.infinity, cplex.infinity, 3.0]
#lb Lower Bound,下界,同上理
my_lb = [0.0, 0.0, 0.0, 2.0]
#变量类型,详见https://www.ibm.com/support/knowledgecenter/SSSA5P_12.9.0/ilog.odms.cplex.help/refpythoncplex/html/cplex._internal._subinterfaces.VarTypes-class.html
#ctrlF搜索Class Variables即可
#分别表示4各变量的变量类型,C表示Continuous 连续值(浮点数),I表示Integer
my_ctype = "CCCI"
#给4个变量起个名字
my_colnames = ["x1", "x2", "x3", "x4"]
#约束规则
#rows是约束集的左值,数组类型
#每一个元素为一条约束规则,也为一个数组类型,包含2个元素,前者为约束变量的名称列表,后者为系数关系
my_rows = [[["x1", "x2", "x3", "x4"], [-1.0, 1.0, 1.0, 10.0]],
[["x1", "x2", "x3"], [1.0, -3.0, 1.0]],
[["x2", "x4"], [1.0, -3.5]]]
#rhs是约束规则集的右值
my_rhs = [20.0, 30.0, 0.0]
#约束规则集的左右值关系,详见https://www.ibm.com/support/knowledgecenter/SSSA5P_12.9.0/ilog.odms.cplex.help/refcallablelibrary/cpxapi/getsense.html
#L表示小于等于,E表示等于
my_sense = "LLE"
#给各条约束规则起名字
my_rownames = ["r1", "r2", "r3"]
try:
#实例化一个cplex优化器
prob = cplex.Cplex()
#求解的目标为目标函数的最小值
prob.objective.set_sense(prob.objective.sense.maximize)
#添加变量:变量在目标函数里的系数,变量的上下界,变量类型,名称
prob.variables.add(obj=my_obj, lb=my_lb, ub=my_ub, types=my_ctype,
names=my_colnames)
#添加约束:约束左值,等式/不等式符号,右值,名称
prob.linear_constraints.add(lin_expr=my_rows, senses=my_sense,
rhs=my_rhs, names=my_rownames)
#求解
prob.solve()
#显示最优情况下的变量值
x = prob.solution.get_values()
print(x)
#显示最优情况下的目标值
objective_value = prob.solution.get_objective_value()
print(objective_value)
except CplexError as exc:
print(exc)
运行可以看到如下结果
Docplex实例
在学习了以上内容后我想自己建模解一些比较复杂的优化问题,
发现CplexPythonAPI中提供的接口还是很不人性化的,
prob.indicator_constraints.add() #添加当且仅当约束
prob.linear_constraints.add() #添加线性约束
prob.pwl_constraints.add() #添加分段约束
prob.quadratic_constraints.add() #添加平方约束
想要实现这样的约束还是蛮复杂的
而在网上搜刮了一番资料也没找到相关的cplex实例,反而是Docplex库对cplex的Python实现的Api还比较清晰明了
因此果断转用Docplex:
使用docplex实现的案例:
优化的是一个简单的拓扑工序:
其中X表示要优化出来的各个工区起始时间,Y为常数,各工序时长
并且有一个特殊限制,X2和X5不可以同时进行
mdl = Model(name='schedule')
#告诉cplex开辟这些自变量空间
x1 = mdl.integer_var(name='x1')
x2 = mdl.integer_var(name='x2')
x3 = mdl.integer_var(name='x3')
x4 = mdl.integer_var(name='x4')
x5 = mdl.integer_var(name='x5')
x6 = mdl.integer_var(name='x6')
#一些常数
y=[0,100,50,500,50,400,100]
#添加约束,约束表达式与名称
mdl.add_constraint(x1 + y[1] <= x2, 'c1')
mdl.add_constraint(x2 + y[2] <= x3, 'c2')
mdl.add_constraint(x4 + y[4] <= x5, 'c3')
mdl.add_constraint(x5 + y[5] <= x6, 'c4')
#一种特殊的约束,if_then(表达式1, 表达式2)
#如果满足表达式1,那么就需要满足表达式2的约束
mdl.add(mdl.if_then(x5 >= x2, x5 - x2 >= y[2]))
mdl.add(mdl.if_then(x2 >= x5, x5 - x2 >= -y[5]))
mdl.minimize(x6 + y[6])
mdl.solve()
for v in mdl.iter_integer_vars():
print(v," = ",v.solution_value)
print(mdl.solution.get_objective_value())
完成