常见的定义变量是:
m.addvars()
// An highlighted block
addVars ( *indices, lb=0.0, ub=GRB.INFINITY, obj=0.0, vtype=GRB.CONTINUOUS,
name="" );
在Gurobi中主要用到的变量类型 vtype=
GRB.CONTINUOUS——连续变量(Gurobi默认变量类型,可以省略)
GRB.BINARY——二进制变量(0-1)
GRB.INTEGER——整数变量(1,2,3,4,5等整数)
默认下界为0。
当下界比0小,或是需要减少变量规模时,可以自行设置。
上界默认为无穷大。即GRB.INFINITY
变量边界尽可能明确,不要设置lb=-GRB.INFINITY,ub=GRB.INFINITY.
(1)线性化处理
基本是用0&1变量做中间变量,进行转化。
(2)指数或对数形式有专门的语句
// 如指数型a^x:一般底数;以e为底
addGenConstrExp ( xvar, yvar, name="", options="" );
如:
# y = 3^x
gc = model.addGenConstrExpA(x, y, 3.0, "expa")
# y = exp(x)>>>y=e^x
gc = model.addGenConstrExp(x, y)
//幂指型x^a:一般幂指,以e为底,两者写法一致
addGenConstrPow ( xvar, yvar, a, name="", options="" )
如:
# y = x^3.5
gc = model.addGenConstrPow(x, y, 3.5, "gf", "FuncPieces=1000")
通常作为中间变量,需要使用循环,然后其他变量线性表达式。
我们添加变量,目标函数和约束条件后,此时模型还没有并修改。模型此时是等待更新的状态。更新有三种方式:
(1)model.update(),即更新模型,比如下述代码部分。
(2)model.optimize(),这种是我们用的最多的。即直接求解,就包含了更新这一过程,所以更新与否我们平时是忽略的。
(3)model.write(),将模型导出成本地模型文件。
{(10, 0): <gurobi.Var *Awaiting Model Update*>,
(10, 1): <gurobi.Var *Awaiting Model Update*>,}
>>>model.getVars()
Out[2]: []
>>>model.update()
>>>model.getVars()
Out[4]:
[<gurobi.Var x_10_0>,
<gurobi.Var x_10_1>]
3.2 获取解的取值
当调用model.optimize()求解完模型后,此时再调用model.getVars(),可以在上述getVars()基础上获得变量的取值。注意此时获取的是所有的变量。
假如我们只想获取某一类变量,可以用:var.VarName.startswith(‘x’),这样的意思是获取x打头的变量。
var.x是获取变量的值,通常是用遍历的方式打印最终的结果,或是根据varName获取变量的值。
# print optimal solution
for var in model.getVars():
if (var.x > 0):
print(var.varName, '\t', var.x) # '\t' 空格,展示方便
# 如varName = 'x_0_1_0'
model.getVarByName('x_0_1_0').x # 即model.getVarByName(varName)根据变量名提取变量
备注:假如获取索引可以用
'x_0_1_0'.split('_') # 按照'_'进行分割
['x', '0', '1', '0']
观察模型预处理时间、解的状态。
(1)预处理时间过久的话,可以自己在变量上下界那块设置;
(2)解是什么状态?
如果是不可行,infeasible solution的话。要么是模型写错了,要么是模型对了编程写错了(好好检查)。
//模型写错,也就是约束有矛盾的话可以调用:
m.computellS()
m.write(model.ilp)
//或者下面这种,直接输出矛盾的约束名称:
if m.status == GRB.Status.INFEASIBLE:
print('Optimization was stopped with status %d' % m.status)
# do IIS, find infeasible constraints
m.computeIIS()
for c in m.getConstrs():
if c.IISConstr:
print('%s' % c.constrName)
gurobi提供了一个函数computeIIS()可以帮我们迅速锁定出是有问题的约束条件。此时输出的ilp文件会打印出互相矛盾的约束,链接: 检查修改即可。
其实,正常情况下也建议m.write(model.lp)文件,核对一下约束。
注意,代码中的是ilp文件,只打印出互相矛盾的约束,而lp文件打出所有的约束。不一样的。
(3)检查模型是否正确
a)输出lp文件,一一核对;
b)检查解是否对,如果不对,那么修改模型。
(1)gurobi在求解的时候,整数变量(0-1变量)也以浮点数据在进行处理,因此在最终结果中可能会带小数。误差在1e-5内,都算作正常误差。
如果想得到不带小数的结果,需要设置 IntegralityFocus (仅限 9.1 或以后版本)参数,即:可以设置为:
m.Params.IntegralityFocus=1
对Python+Gurobi建模中,所有参数设置都可以写为: ‘Model.Params. xxxx = 1e-XX’ 的形式 ,如Model.Params. xxxx = 1e-9,表示精度在1e-9;再比如Model.Params. xxxx = 1e+inf,表示设置为1。
(2)range() 函数可创建一个整数列表,也就是给出 Ni=4,range(Ni)会创造 0,1,2,3四个整数数字, 而不是 1, 2, 3, 4,这是Python规定的。
for i in range(N_i) 表示令i 分别等于0,1,2,3,然后用于后续循环。
x_c=np.zeros((N_i,N_j))
利用 'np.zeros()' 定义一个名为'x_c',具有N_i行N_j列的全0行列式。
(3)gurobi中只能两个变量相乘,多了的话就要设置中间变量了。
(4)不要设置变量上下界为无穷大,否则会出错。
按照Gurobi 官方说法:
变量、约束条件、目标的系数取值合适的范围,使得变量的优化值范围在【-1e+4,1e+4】 之间,约束取值在【-1e+4, 1e+4】之间,目标取值【-1e+4, 1e+4】之间;
最大系数/最小系数 的比值在 1e+9 之内。
我们重新对变量 、 进行定义。