数学建模学习(92):gurobipy详细入门教程【MLP、MIP模型、仓库调度模型、单/多目标优化、敏感性分析】

这一篇内容作为我的个人学习笔记,感兴趣的可以学习下哦。当然,你若没有兴趣就可以跳过。

一、介绍

声明:未经允许,不得转载——CSDN:川川菜鸟

独立第三方优化器评估报告显示,Gurobi 以卓越的性能跻身大规模优化器新领袖地位,成为性价比最为优秀的企业大规模优化器首选。

Gurobi是由美国 Gurobi Optimization 公司开发新一代大规模优化器。无论在生产制造领域,还是在金融、保险、交通、服务等其他各种领域,当实际问题越来越复杂,问题规模越来越庞大的时候,我们需要一个经过证明可以信赖的大规模优化工具,为我们的决策提供质量保证,为我们增强信心。在理论和实践中,Gurobi 优化工具都被证明是全球性能领先的大规模优化器,具有突出的性价比,可以为客户在开发和实施中极大降低成本。

Gurobi 是全局优化器,支持的模型类型包括:
(1)连续和混合整数线性问题
(2)凸目标或约束连续和混合整数二次问题
(3)非凸目标或约束连续和混合整数二次问题
(4)含有对数、指数、三角函数、高阶多项式目标或约束,以及任何形式的分段约束的非线性问题
(5)含有绝对值、最大值、最小值、逻辑与或非目标或约束的非线性问题

二、安装配置

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
然后。。点了yes就重启电脑。然后去获取许可证。更详细过程参考这位博主:

https://blog.csdn.net/weixin_41596280/article/details/89112302

申请许可证的方式建议看这个

http://www.gurobi.cn/NewsView1.Asp?id=4

但是好像,不申请许可证好像也可以直接pip后使用。。。你可以试试。

该工具支持的语言很多,这里我只介绍Python的实现:
在这里插入图片描述

三、代码基本流程

Python+Gurobi 建立数学规划模型时,通常会按照设置变量、更新变量空间、设置目标函数、设置约束条件、执行最优化的顺序进行。
在这里插入图片描述

import gurobipy

# 创建模型
MODEL = gurobipy.Model()

# 创建变量
X = MODEL.addVar(vtype=gurobipy.GRB.INTEGER,name="X")

# 更新变量环境
MODEL.update()

# 创建目标函数
MODEL.setObjective('目标函数表达式', gurobipy.GRB.MINIMIZE)

# 创建约束条件
MODEL.addConstr('约束表达式,逻辑运算')

# 执行模型
MODEL.optimize()

# 输出模型结果
print("Obj:", MODEL.objVal)
for x in X:
    print(f"{x.varName}:{round(x.X,3)}")

四、MLP模型

似乎不用上述的安装步骤也可以,直接用下方的pip下载即可使用。 模块安装:

pip install gurobipy

问题和代码:

# 案例如下
#  maximize
#        x +   y + 2 z
#  subject to
#        x + 2 y + 3 z <= 4
#        x +   y       >= 1
#        x, y, z binary
import gurobipy as gp
from gurobipy import GRB

try:
    # 创建模型
    m = gp.Model("mip1")

    # 创建变量
    x = m.addVar(vtype=GRB.BINARY, name="x")
    y = m.addVar(vtype=GRB.BINARY, name="y")
    z = m.addVar(vtype=GRB.BINARY, name="z")

    # 创建目标
    m.setObjective(x + y + 2 * z, GRB.MAXIMIZE)

    # 添加约束: x + 2 y + 3 z <= 4
    m.addConstr(x + 2 * y + 3 * z <= 4, "c0")

    # 添加第二个约束: x + y >= 1
    m.addConstr(x + y >= 1, "c1")

    # 优化模型
    m.optimize()

    # 打印求解变量名称和对应值
    for v in m.getVars():
        print('%s %g' % (v.varName, v.x))

    # 最优解
    print('Obj: %g' % m.objVal)

运行如下:

Restricted license - for non-production use only - expires 2023-10-25
Gurobi Optimizer version 9.5.2 build v9.5.2rc0 (win64)
Thread count: 6 physical cores, 12 logical processors, using up to 12 threads
Optimize a model with 2 rows, 3 columns and 5 nonzeros
Model fingerprint: 0x98886187
Variable types: 0 continuous, 3 integer (3 binary)
Coefficient statistics:
  Matrix range     [1e+00, 3e+00]
  Objective range  [1e+00, 2e+00]
  Bounds range     [1e+00, 1e+00]
  RHS range        [1e+00, 4e+00]
Found heuristic solution: objective 2.0000000
Presolve removed 2 rows and 3 columns
Presolve time: 0.00s
Presolve: All rows and columns removed

Explored 0 nodes (0 simplex iterations) in 0.00 seconds (0.00 work units)
Thread count was 1 (of 12 available processors)

Solution count 2: 3 2 

Optimal solution found (tolerance 1.00e-04)
Best objective 3.000000000000e+00, best bound 3.000000000000e+00, gap 0.0000%
x 1
y 0
z 1
Obj: 3

这个就是最优解啦:
在这里插入图片描述

五、MIP 模型

通过矩阵方式计算,案例和代码如下:

#        x +   y + 2 z
#  subject to
#        x + 2 y + 3 z <= 4
#        x +   y       >= 1
#        x, y, z binary

import gurobipy as gp
from gurobipy import GRB
import numpy as np
import scipy.sparse as sp

try:

    #创建模型
    m = gp.Model("matrix1")

    # 将矩阵变量添加到模型中:在这种情况下,矩阵变量由 3 个二进制变量的一维数组组成。
    x = m.addMVar(shape=3, vtype=GRB.BINARY, name="x")

    # 目标是通过使用重载@ 运算符计算常数向量和矩阵变量之间的点积来构建的。请注意,常数向量必须与我们的矩阵变量具有相同的长度。
    # 第二个参数表明意义是最大化。
    obj = np.array([1.0, 1.0, 2.0])
    m.setObjective(obj @ x, GRB.MAXIMIZE)

    # 构建(稀疏)约束矩阵
    # 注意,我们将大于约束乘以将其乘以-1<转换为小于约束。
    val = np.array([1.0, 2.0, 3.0, -1.0, -1.0]) # 两个约束的左侧系数值
    row = np.array([0, 0, 0, 1, 1]) # 分别对应行。(0表示第一行,1表示第二行)
    col = np.array([0, 1, 2, 0, 1]) # 分别表示的列。(0表示第一列)

    A = sp.csr_matrix((val, (row, col)), shape=(2, 3))

    # 构建 rhs 向量。也就是约束右边的值。
    rhs = np.array([4.0, -1.0])

    # 添加约束模型。使用重载的@运算符构建一个线性矩阵表达式,然后使用重载的小于或等于运算符添加两个约束
    m.addConstr(A @ x <= rhs, name="c")

    # 优化模型
    m.optimize()

    print(x.X)
    print('Obj: %g' % m.objVal)

except gp.GurobiError as e:
    print('Error code ' + str(e.errno) + ": " + str(e))

except AttributeError:
    print('Encountered an attribute error')

结果如下:

Optimize a model with 2 rows, 3 columns and 5 nonzeros
Model fingerprint: 0x8d4960d3
Variable types: 0 continuous, 3 integer (3 binary)
Coefficient statistics:
  Matrix range     [1e+00, 3e+00]
  Objective range  [1e+00, 2e+00]
  Bounds range     [1e+00, 1e+00]
  RHS range        [1e+00, 4e+00]
Found heuristic solution: objective 2.0000000
Presolve removed 2 rows and 3 columns
Presolve time: 0.00s
Presolve: All rows and columns removed

Explored 0 nodes (0 simplex iterations) in 0.00 seconds (0.00 work units)
Thread count was 1 (of 12 available processors)

Solution count 2: 3 2 

Optimal solution found (tolerance 1.00e-04)
Best objective 3.000000000000e+00, best bound 3.000000000000e+00, gap 0.0000%
[1. 0. 1.]
Obj: 3

最终结果只需要看最下面部分即可:

Best objective 3.000000000000e+00, best bound 3.000000000000e+00, gap 0.0000%
[1. 0. 1.]
Obj: 3

六、仓库调度模型

在这里插入图片描述
案例:两种商品(铅笔和钢笔)在两个城市(底特律和丹佛)生产,并且必须运送到三个城市(波士顿、纽约和西雅图)的仓库以满足给定的需求。运输网络中的每条弧线都有一个与之相关的单位成本,以及最大的总运输能力。满足需求(‘inflow[h,i]’)。交通网络上的流量必须遵守弧线容量限制 (‘容量[i,j]’)。目标是最小化弧的总和运输成本(‘cost[i,j]’)。

(如果案例描述不清楚,请看代码注释),详细实现如下:


import gurobipy as gp
from gurobipy import GRB

# 基础数据
commodities = ['Pencils', 'Pens'] # 两种产品
nodes = ['Detroit', 'Denver', 'Boston', 'New York', 'Seattle'] # 五个节点(五个城市)


# 网络包含 5 个节点和 6 个弧长(距离)
arcs, capacity = gp.multidict({
    
    
    ('Detroit', 'Boston'):   100,
    ('Detroit', 'New York'):  80,
    ('Detroit', 'Seattle'):  120,
    ('Denver',  'Boston'):   120,
    ('Denver',  'New York'): 120,
    ('Denver',  'Seattle'):  120})

# 三元组   商品-出发地-目的地的成本
# 一旦创建了这个字典,将一个单位商品 h从节点移动i到的成本j可以查询为 cost[(h,i,j)]
# Python 允许在使用元组索引字典时省略括号,因此可以将其缩短为cost[h,i,j].
cost = {
    
    
    ('Pencils', 'Detroit', 'Boston'):   10,
    ('Pencils', 'Detroit', 'New York'): 20,
    ('Pencils', 'Detroit', 'Seattle'):  60,
    ('Pencils', 'Denver',  'Boston'):   40,
    ('Pencils', 'Denver',  'New York'): 40,
    ('Pencils', 'Denver',  'Seattle'):  30,
    ('Pens',    'Detroit', 'Boston'):   20,
    ('Pens',    'Detroit', 'New York'): 20,
    ('Pens',    'Detroit', 'Seattle'):  80,
    ('Pens',    'Denver',  'Boston'):   60,
    ('Pens',    'Denver',  'New York'): 70,
    ('Pens',    'Denver',  'Seattle'):  30}

# 初始化节点的需求/供应数据。正值表示需求,而负值表示供应。即表达某个城市对某个商品的需求/供应数据。
inflow = {
    
    
    ('Pencils', 'Detroit'):   50,
    ('Pencils', 'Denver'):    60,
    ('Pencils', 'Boston'):   -50,
    ('Pencils', 'New York'): -50,
    ('Pencils', 'Seattle'):  -10,
    ('Pens',    'Detroit'):   60,
    ('Pens',    'Denver'):    40,
    ('Pens',    'Boston'):   -40,
    ('Pens',    'New York'): -30,
    ('Pens',    'Seattle'):  -30}

# 创建优化模型
m = gp.Model('netflow')

# 创建变量。flow[c,i,j]将捕获商品c从节点i到节点的流动j。
flow = m.addVars(commodities, arcs, obj=cost, name="flow")

# 容量约束。这里设置为弧上的流变量之和必须小于或等于该弧的容量
m.addConstrs(
    (flow.sum('*', i, j) <= capacity[i, j] for i, j in arcs), "cap")

# 如果您更喜欢自己进行循环,则可以通过以下循环获得等效的结果
# for i, j in arcs:
#   m.addConstr(sum(flow[h, i, j] for h in commodities) <= capacity[i, j],
#               "cap[%s, %s]" % (i, j))


# 流量守恒约束。流入该节点的流量之和加上该节点的外部流入量必须等于流出该节点的流量之和。
m.addConstrs(
    (flow.sum(h, '*', j) + inflow[h, j] == flow.sum(h, j, '*')
        for h in commodities for j in nodes), "node")


#计算最优解
m.optimize()

# 打印结果
if m.status == GRB.OPTIMAL:
    solution = m.getAttr('x', flow)
    for h in commodities:
        print('\n %s的最优解 :' % h)
        for i, j in arcs:
            if solution[h, i, j] > 0:
                print('%s -> %s: %g' % (i, j, solution[h, i, j]))

得到结果为:

Restricted license - for non-production use only - expires 2023-10-25
Gurobi Optimizer version 9.5.2 build v9.5.2rc0 (win64)
Thread count: 6 physical cores, 12 logical processors, using up to 12 threads
Optimize a model with 16 rows, 12 columns and 36 nonzeros
Model fingerprint: 0xc43e5943
Coefficient statistics:
  Matrix range     [1e+00, 1e+00]
  Objective range  [1e+01, 8e+01]
  Bounds range     [0e+00, 0e+00]
  RHS range        [1e+01, 1e+02]
Presolve removed 16 rows and 12 columns
Presolve time: 0.00s
Presolve: All rows and columns removed
Iteration    Objective       Primal Inf.    Dual Inf.      Time
       0    5.5000000e+03   0.000000e+00   2.000000e+01      0s
Extra simplex iterations after uncrush: 1
       1    5.5000000e+03   0.000000e+00   0.000000e+00      0s

Solved in 1 iterations and 0.00 seconds (0.00 work units)
Optimal objective  5.500000000e+03

 Pencils的最优解 :
Detroit -> Boston: 50
Denver -> New York: 50
Denver -> Seattle: 10

七、线性规划模型

在这里插入图片描述

建立模型:
在这里插入图片描述
代码如下:

import gurobipy

# 创建模型
MODEL = gurobipy.Model()

# 创建变量
x1 = MODEL.addVar(vtype=gurobipy.GRB.INTEGER, name='x1')
x2 = MODEL.addVar(ub=3, vtype=gurobipy.GRB.INTEGER, name='x2')
x1_ = MODEL.addVars(range(1, 3), vtype=gurobipy.GRB.INTEGER, name='x1_')
x2_ = MODEL.addVars(range(1, 6), vtype=gurobipy.GRB.INTEGER, name='x2_')
# 更新变量环境
MODEL.update()

# 创建目标函数
MODEL.setObjective(100 * x1 + 40 * x2, sense=gurobipy.GRB.MINIMIZE)

# 创建约束条件
MODEL.addConstr(x1 + x2_[1] >= 4, name='9:00-10:00')
MODEL.addConstr(x1 + x2_[1] + x2_[2] >= 3, name='10:00-11:00')
MODEL.addConstr(x1 + x2_[1] + x2_[2] + x2_[3] >= 4, name='11:00-12:00')
MODEL.addConstr(x1_[1] + x2_[1] + x2_[2] + x2_[3] + x2_[4]>= 6, name='12:00-13:00')
MODEL.addConstr(x1_[2] + x2_[2] + x2_[3] + x2_[4] + x2_[5]>= 5, name='13:00-14:00')
MODEL.addConstr(x1 + x2_[3] + x2_[4] + x2_[5]>= 6, name='14:00-15:00')
MODEL.addConstr(x1 + x2_[4] + x2_[5] >= 8, name='15:00-16:00')
MODEL.addConstr(x1 + x2_[5]>= 8, name='16:00-17:00')

# 此处, sum(x1_) 和 x1_.sum() 结果不同, 因为 sum(x1_) 对字典进行键相加
# 更标准的写法是使用 gurobipy.quicksum(x1_) 和 gurobipy.quicksum(x2_)
MODEL.addConstr(x1_.sum() == x1, name='x1')
MODEL.addConstr(x2_.sum() == x2, name='x2')

# 执行最优化
MODEL.optimize()

结果如下:

Root relaxation: objective 7.700000e+02, 3 iterations, 0.00 seconds (0.00 work units)

    Nodes    |    Current Node    |     Objective Bounds      |     Work
 Expl Unexpl |  Obj  Depth IntInf | Incumbent    BestBd   Gap | It/Node Time

     0     0  770.00000    0    3  880.00000  770.00000  12.5%     -    0s
H    0     0                     820.0000000  770.00000  6.10%     -    0s
     0     0  770.00000    0    3  820.00000  770.00000  6.10%     -    0s

Explored 1 nodes (3 simplex iterations) in 0.02 seconds (0.00 work units)
Thread count was 12 (of 12 available processors)

Solution count 2: 820 880 

Optimal solution found (tolerance 1.00e-04)
Best objective 8.200000000000e+02, best bound 8.200000000000e+02, gap 0.0000%

八、线性规划模型(二)

问题如下:
在这里插入图片描述
代码编写:

import gurobipy

# 创建模型
c = [8, 10, 7, 6, 11, 9] # 目标函数的系数
# 约束函数的系数
p = [[12, 9, 25, 20, 17, 13],
     [35, 42, 18, 31, 56, 49],
     [37, 53, 28, 24, 29, 20]]
# 约束函数右侧的值
r = [60, 150, 125]
MODEL = gurobipy.Model()

# 创建变量。六个变量,上下限分别为10。
x = MODEL.addVars(6, lb=0, ub=1, name='x')

# 更新变量环境
MODEL.update()

# 创建目标函数。设置求解最小值。
MODEL.setObjective(x.prod(c), gurobipy.GRB.MINIMIZE)

# 创建约束条件
MODEL.addConstrs(x.prod(p[i]) >= r[i] for i in range(3))

# 执行线性规划模型
MODEL.optimize()
print("最优解为:", MODEL.objVal)
for v in MODEL.getVars():
    print(f"{v.varName}:{round(v.x, 3)}")

结果如下:

Optimal objective  3.215463133e+01
最优解为: 32.154631330359486
x[0]1.0
x[1]0.623
x[2]0.343
x[3]1.0
x[4]0.048
x[5]1.0

九、单目标优化模型

MODEL.setObjective(expression, sense=None)

  • expression: 表达式,可以是一次或二次函数类型
  • sense:求解类型,可以是GRB.MINIMIZE 或 GRB.MAXIMIZE

例如:

MODEL.setObjective(8 * x1 + 10 * x2 + 7 * x3 + 6 * x4 + 11 * x5 + 9 * x6, gurobipy.GRB.MINIMIZE)

我随便编的约束,假设变量都小于10,求目标函数最大值:


import gurobipy as gp
from gurobipy import GRB

try:
    # 创建模型
    m = gp.Model()

    # 创建变量
    x1 = m.addVar(vtype=GRB.BINARY, name="x1")
    x2 = m.addVar(vtype=GRB.BINARY, name="x2")
    x3 = m.addVar(vtype=GRB.BINARY, name="x3")
    x4 = m.addVar(vtype=GRB.BINARY, name="x4")
    x5 = m.addVar(vtype=GRB.BINARY, name="x5")
    x6 = m.addVar(vtype=GRB.BINARY, name="x6")

    # 创建目标,求最小值
    m.setObjective(8 * x1 + 10 * x2 + 7 * x3 + 6 * x4 + 11 * x5 + 9 * x6, GRB.MAXIMIZE)

    # 添加约束.我随便设置的几个约束。
    m.addConstr(x1 <= 10, "c0")
    # 添加第二个约束:
    m.addConstr(x2 <= 10, "c1")
    m.addConstr(x3 <= 10, "c2")
    m.addConstr(x4 <= 10, "c3")
    m.addConstr(x5 <= 10, "c4")
    m.addConstr(x6 <= 10, "c5")

    # 优化模型
    m.optimize()

    # 打印求解变量名称和对应值
    for v in m.getVars():
        print('%s %g' % (v.varName, v.x))

    # 最优解
    print('Obj: %g' % m.objVal)

except gp.GurobiError as e:
    print('Error code ' + str(e.errno) + ': ' + str(e))

except AttributeError:
    print('Encountered an attribute error')

结果如下:

Solution count 1: 51 

Optimal solution found (tolerance 1.00e-04)
Best objective 5.100000000000e+01, best bound 5.100000000000e+01, gap 0.0000%
x1 1
x2 1
x3 1
x4 1
x5 1
x6 1
Obj: 51

十、多目标优化

默认优化最小值,如果想得到最大值,就是目标函数前面加个负号。

  • expression: 表达式,可以是一次或二次函数类型
  • index: 目标函数对应的序号 (默认 0,1,2,…), 以 index=0 作为目标函数的值, 其余值需要另外设置参数
  • priority: 分层序列法多目标决策优先级(整数值), 值越大优先级越高
  • weight: 线性加权多目标决策权重(在优先级相同时发挥作用)
  • abstol: 分层序列法多目标决策时允许的目标函数值最大的降低量
  • reltol: 分层序列法多目标决策时允许的目标函数值最大的降低比率 reltol*|目标函数值|

10.1 线性加权方法

注意加权和为1,这基本知识我就不说了,在我的数模专栏讲过这种基础知识,那一篇文章我是基于Matlab对多目标求解。

案例:

第一个目标:x + y
第二个目标:x - 5 * y
约束:x和y都小于等于10

代码如下:


import gurobipy as gp
from gurobipy import GRB

try:
    # 创建模型
    m = gp.Model()

    # 创建变量
    x = m.addVar(vtype=GRB.BINARY, name="x")
    y = m.addVar(vtype=GRB.BINARY, name="y")

    # 创建目标,默认求最小值
    m.setObjectiveN(x + y, index=0, weight=1, name='obj1')
    m.setObjectiveN(x - 5 * y, index=1, weight=-2, name='obj2')

    # 添加约束.我随便设置的几个约束。
    m.addConstr(x <= 10, "c0")
    # 添加第二个约束:
    m.addConstr(y <= 10, "c1")

    # 优化模型
    m.optimize()

    for v in m.getVars():
        print('%s %g' % (v.varName, v.x))
    # 获取最优解
    m.setParam(GRB.Param.ObjNumber, 0)
    print("第一个最优解为:", m.ObjNVal)
    m.setParam(GRB.Param.ObjNumber, 1)
    print("第二个最优解为:", m.ObjNVal)

# 异常处理
except gp.GurobiError as e:
    print('Error code ' + str(e.errno) + ': ' + str(e))

except AttributeError:
    print('Encountered an attribute error')

结果:

ulti-objectives: solved in 0.00 seconds (0.00 work units), solution count 1

x 1
y -0
第一个最优解为: 1.0
第二个最优解为: 1.0

注意:权重的设置对结果影响很大,这个方法其实是不太好的,一般要有具体场景才能对权重做一个更好的设置。

如果我把两个目标函数的权重都改为0.5,则结果如下:

Multi-objectives: solved in 0.00 seconds (0.00 work units), solution count 1

x -0
y -0
第一个最优解为: 0.0
第二个最优解为: 0.0

10.1 分层序列法

两个目标不变,但是我们可以给它们设置不同的优先级。实现如下:

import gurobipy as gp
from gurobipy import GRB

try:
    # 创建模型
    m = gp.Model()

    # 创建变量
    x = m.addVar(vtype=GRB.BINARY, name="x")
    y = m.addVar(vtype=GRB.BINARY, name="y")

    # 创建目标,默认求最小值.先优化 Obj1,再优化 Obj2(按照 priority 的大小关系)
    m.setObjectiveN(x + y, index=0, priority=5, name='obj1')
    m.setObjectiveN(x - 5 * y, index=1, priority=1, name='obj2')

    # 添加约束.我随便设置的几个约束。
    m.addConstr(x <= 10, "c0")
    # 添加第二个约束:
    m.addConstr(y <= 10, "c1")

    # 优化模型
    m.optimize()

    # 获取最优解
    m.setParam(GRB.Param.ObjNumber, 0)
    print("第一个最优解为:", m.ObjNVal)
    m.setParam(GRB.Param.ObjNumber, 1)
    print("第二个最优解为:", m.ObjNVal)

# 异常处理
except gp.GurobiError as e:
    print('Error code ' + str(e.errno) + ': ' + str(e))

except AttributeError:
    print('Encountered an attribute error')

执行如下:

Multi-objectives: solved in 0.00 seconds (0.00 work units), solution count 1

第一个最优解为: 0.0
第二个最优解为: 0.0

10.3 混合优化方法

混合权重和优先值实现,如下:

import gurobipy as gp
from gurobipy import GRB

try:
    # 创建模型
    m = gp.Model()

    # 创建变量
    x = m.addVar(vtype=GRB.BINARY, name="x")
    y = m.addVar(vtype=GRB.BINARY, name="y")

    # 创建目标,默认求最小值.先优化 Obj1 再优化 Obj2 最后相加作为目标值
    m.setObjectiveN(x + y, index=0, weight=0.5, priority=5, name='obj1')
    m.setObjectiveN(x - 5 * y, index=1, weight=0.5, priority=1, name='obj2')

    # 添加约束.我随便设置的几个约束。
    m.addConstr(x <= 10, "c0")
    # 添加第二个约束:
    m.addConstr(y <= 10, "c1")

    # 优化模型
    m.optimize()

    # 获取x的值
    for v in m.getVars():
        print('%s %g' % (v.varName, v.x))
    # 获取最优解
    m.setParam(GRB.Param.ObjNumber, 0)
    print("第一个最优解为:", m.ObjNVal)
    m.setParam(GRB.Param.ObjNumber, 1)
    print("第二个最优解为:", m.ObjNVal)

# 异常处理
except gp.GurobiError as e:
    print('Error code ' + str(e.errno) + ': ' + str(e))

except AttributeError:
    print('Encountered an attribute error')


结果:

Multi-objectives: solved in 0.00 seconds (0.00 work units), solution count 1

x -0
y -0
第一个最优解为: 0.0
第二个最优解为: 0.0

补充获取最优解的代码:

    m.setParam(GRB.Param.ObjNumber, 0)
    print("第一个最优解为:", m.ObjNVal)
    m.setParam(GRB.Param.ObjNumber, 1)
    print("第二个最优解为:", m.ObjNVal)

等效于:

    for i in range(m.NumObj):
        m.setParam(GRB.Param.ObjNumber, i)
        print(f"第 {i + 1}最优解 = {m.ObjNVal}")

十一、模型敏感性分析

基础理论不做讲解,请看我的数模专栏中的敏感性分析讲解。

import gurobipy

# 创建模型
c = [8, 10, 7, 6, 11, 9]  # 目标函数的系数
# 约束函数的系数
p = [[12, 9, 25, 20, 17, 13],
     [35, 42, 18, 31, 56, 49],
     [37, 53, 28, 24, 29, 20]]
# 约束函数右侧的值
r = [60, 150, 125]
MODEL = gurobipy.Model()

# 创建变量。六个变量,上下限分别为10。
x = MODEL.addVars(6, lb=0, ub=1, name='x')

# 更新变量环境
MODEL.update()

# 创建目标函数。设置求解最小值。
MODEL.setObjective(x.prod(c), gurobipy.GRB.MINIMIZE)

# 创建约束条件
MODEL.addConstrs(x.prod(p[i]) >= r[i] for i in range(3))

# 执行线性规划模型
MODEL.optimize()
# print("最优解为:", MODEL.objVal)
# for v in MODEL.getVars():
#     print(f"{v.varName}:{round(v.x, 3)}")

import gurobipy
import pandas as pd


def LP_Model_Analysis(MODEL, precision=3):
    if MODEL.status == gurobipy.GRB.Status.OPTIMAL:
        pd.set_option('display.precision', precision)  # 设置精度
        print("\n找到全局最优解.")
        print(f"Objective Sense: {'MINIMIZE' if MODEL.ModelSense is 1 else 'MAXIMIZE'}")
        print(f"Objective Value= {MODEL.ObjVal}")
        try:
            print(pd.DataFrame([[var.X, var.RC] for var in MODEL.getVars()],
                               index=[var.Varname for var in MODEL.getVars()], columns=["Value", "Reduced Cost"]))
            print(pd.DataFrame([[Constr.Slack, Constr.pi] for Constr in MODEL.getConstrs()],
                               index=[Constr.constrName for Constr in MODEL.getConstrs()],
                               columns=["Slack or Surplus", "Dual Price"]))
            print("\nRanges in which the basis is unchanged: ")
            print(pd.DataFrame([[var.Obj, var.SAObjLow, var.SAObjUp] for var in MODEL.getVars()],
                               index=[var.Varname for var in MODEL.getVars()],
                               columns=["Cofficient", "Allowable Minimize", "Allowable Maximize"]))
            print("Righthand Side Ranges:")
            print(pd.DataFrame([[Constr.RHS, Constr.SARHSLow, Constr.SARHSUp] for Constr in MODEL.getConstrs()],
                               index=[Constr.constrName for Constr in MODEL.getConstrs()],
                               columns=["RHS", "Allowable Minimize", "Allowable Maximize"]))
        except:
            print(pd.DataFrame([var.X for var in MODEL.getVars()], index=[var.Varname for var in MODEL.getVars()],
                               columns=["Value"]))
            print(pd.DataFrame([Constr.Slack for Constr in MODEL.getConstrs()],
                               index=[Constr.constrName for Constr in MODEL.getConstrs()],
                               columns=["Slack or Surplus"]))

LP_Model_Analysis(MODEL)

结果如下:

找到全局最优解.
Objective Sense: MINIMIZE
Objective Value= 32.154631330359486
      Value  Reduced Cost
x[0]  1.000        -0.336
x[1]  0.623         0.000
x[2]  0.343         0.000
x[3]  1.000        -1.816
x[4]  0.048         0.000
x[5]  1.000        -0.044
    Slack or Surplus  Dual Price
R0               0.0       0.111
R1               0.0       0.127
R2               0.0       0.069

Ranges in which the basis is unchanged: 
      Cofficient  Allowable Minimize  Allowable Maximize
x[0]         8.0                -inf               8.336
x[1]        10.0               9.333              10.429
x[2]         7.0               4.989               7.382
x[3]         6.0                -inf               7.816
x[4]        11.0              10.955              13.975
x[5]         9.0                -inf               9.044
Righthand Side Ranges:
      RHS  Allowable Minimize  Allowable Maximize
R0   60.0              52.520              74.297
R1  150.0             148.310             170.453
R2  125.0             103.308             127.042

Process finished with exit code 0

十二、参考文献

https://www.gurobi.com/documentation/
https://zhuanlan.zhihu.com/p/52371462

猜你喜欢

转载自blog.csdn.net/weixin_46211269/article/details/126339063