Gurobi +Python

  • 1 前言
  • 2 快速入门
    • 2.1 辅助函数
      • 2.1.1 列表推导式/列表解析式
      • 2.1.2 quicksum()
      • 2.1.3 multidict()
      • 2.1.4 tuplelist()
      • 2.1.5 prod() 和 sum() 下标聚合
    • 2.2 添加决策变量 Model.addVar() 和 Model.addVars()
      • 2.2.1 创建一个变量
      • 2.2.2 创建多个变量
      • 2.2.3 添加完变量后需要 `MODEL.update()` 更新变量空间
    • 2.3 添加目标函数 Model.setObjective() 和 Model.setObjectiveN()
      • 2.3.1 单目标优化
      • 2.3.2 多目标优化(默认最小值)
    • 2.4 添加约束条件 Model.addConstr() 和 Model.addConstrs()
      • 2.4.1 创建一个常规一次/二次/等式约束
      • 2.4.2 创建多个常规一次/二次/等式约束
      • 2.4.3 创建一个范围约束
      • 2.4.4 创建一个指示变量约束
    • 2.5 执行最优化 Model.optimize()
    • 2.6查看模型结果
      • 2.6.1 模型是否取得最优解
      • 2.6.2 单目标优化 —— 查看目标函数值
      • 2.6.3 多目标优化 —— 查看目标函数值
      • 2.6.4 查看变量取值
      • 2.6.5 LP 问题灵敏度分析
  • 3 实例:一般线性规划问题
  • 4、 ★佐佑思维公众号提供更多学习学术服务★ 二维码如下:

1 前言

本文源自github文章 wurmen/Gurobi-Python ,并在此基础上进行衍生扩展。

Gurobi 可以解决的数学问题:

线性问题(Linear problems)
二次型目标问题(Quadratic problems)
混合整数线性和二次型问题(Mixed integer linear and quadratic problems)
等等

2 快速入门

在利用 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)}")

2.1 辅助函数

2.1.1 列表推导式/列表解析式

  • 列表推导式基于迭代器进行构造,效率高,常用于遍历、过滤、重复计算,快速生成满足要求的序列。
  • 形式上使用中括号作为定界符

列表推导式以 if - for 为主,主要有以下两种嵌套方式:

# if 在后 —— 过滤元素
[expression for exp1 in sequence1 if condition1for exp2 in sequence2 if condition2...for exp2 in sequence2 if conditionn]
# 符合 condition 条件的值会被储存在列表中,
# 不符合的不保存 (类似于 pass 和 filter 函数)
# if 在前 —— 分段映射
[expression1 if condition1 else expression2 for exp1 in sequence1for exp2 in sequence2...for exp2 in sequence2]
# 嵌套循环
[f'{cl}班学生{num}' for cl in list('ABCDE') for num in range(1,6)] # for 从左到右循环
>>> ['A班学生1', 'A班学生2', 'A班学生3', 'A班学生4', 'A班学生5', 'B班学生1', 'B班学生2', 'B班学生3', 'B班学生4', 'B班学生5', 'C班学生1', 'C班学生2', 'C班学生3', 'C班学生4', 'C班学生5', 'D班学生1', 'D班学生2', 'D班学生3', 'D班学生4', 'D班学生5', 'E班学生1', 'E班学生2', 'E班学生3', 'E班学生4', 'E班学生5']

以上几种可以混合使用,十分高效。

举例

  • 列出当前文件夹下的所有 Python 源文件
[filename for filename in os.listdir() if filename.endswith(('.py', '.pyw'))]
# for 循环遍历 os.listdir() 中的所有的文件,if 过滤以 .py, .pyw 结尾的文件

2.1.2 quicksum()

在 gurobipy 模块中,quicksum 相当于 sum 函数及求和符号:

∑ j ∈ J x i , j ≤ 5 ∀ i ∈ I \sum_{j \in J} x_{i, j} \leq 5 \quad \forall i \in I j∈J∑​xi,j​≤5∀i∈I

for i in I:MODEL.addConstr(quicksum(x[i,j] for j in J)<=5)## 用 sum 时
for i in I:MODEL.addConstr(sum(x[i,j] for j in J)<=5)

要注意: quicksum() 是 gurobi 推荐的用法, 它与 sum() 是一致的,但是出现字典时例外。

2.1.3 multidict()

扩展字典,便于处理同一个对象的不同属性约束。

EMPLOYEE, MIN, MAX, COST, START, END = gurobipy.multidict({"SMITH"   : [6, 8, 30, 6, 20], "JOHNSON": [6, 8, 50, 0, 24], 'WILLIAMS': [6, 8, 30, 0, 24],'JONES'   : [6, 8, 30, 0, 24], 'BROWN': [6, 8, 40, 0, 24], 'DAVIS': [6, 8, 50, 0, 24],'MILLER'  : [6, 8, 45, 6, 18], 'WILSON': [6, 8, 30, 0, 24], 'MOORE': [6, 8, 35, 0, 24],'TAYLOR'  : [6, 8, 40, 0, 24], 'ANDERSON': [2, 3, 60, 0, 6], 'THOMAS': [2, 4, 40, 0, 24],'JACKSON' : [2, 4, 60, 8, 16], 'WHITE': [2, 6, 55, 0, 24], 'HARRIS': [2, 6, 45, 0, 24],'MARTIN'  : [2, 3, 40, 0, 24], 'THOMPSON': [2, 5, 50, 12, 24], 'GARCIA': [2, 4, 50, 0, 24],'MARTINEZ': [2, 4, 40, 0, 24], 'ROBINSON': [2, 5, 50, 0, 24]})

EMPLOYEE 变成了list,而 MIN、MAX 等等则变成了字典

EMPLOYEE = [“SMITH”, “JOHNSON”,…]

MIN = {“SMITH”: 6, “JOHNSON”: 6,…}

2.1.4 tuplelist()

扩展列表元组,可以使用通配符筛选变量组。若使用 tuplelist 创建变量:

Cities= [('A','B'), ('A','C'), ('B','C'),('B','D'),('C','D')]
Routes = gurobipy.tuplelist(Cities)Routes.select('A','*') # 选出所有第一个, 素为 "A" 的, 组# 此外, 对于addVars创建的变量, x.select("*", i, j) 也可以进行筛选
# 可以将 '*' 理解为切片操作(列表的 list[:])

2.1.5 prod() 和 sum() 下标聚合

∑ i ∑ j x i j c i j \sum_{i} \sum_{j} x_{i j} c_{i j} i∑​j∑​xij​cij​

gurobipy.quicksum(cost[i,j] * x[i,j] for i,j in arcs)
# 等价于 x.prod(cost)
# 效果为对应元素相乘再相加

2.2 添加决策变量 Model.addVar() 和 Model.addVars()

2.2.1 创建一个变量

x = MODEL.addVar(lb=0.0, ub=gurobipy.GRB.INFINITY, vtype=gurobipy.GRB.CONTINUOUS, name="")

  • lb = 0.0:变量的下界,默认为 0
  • ub = GRB.INFINITY:变量的上界,默认为无穷大
  • vtype = GRB.CONTINUOUS :变量的类型,默认为连续型,可改为 GRB.BINARY 0-1变量,GRB.INTEGER 整型
  • name = "":变量名,默认为空

使用方法:

x1 = MODEL.addVar(lb=0, ub=1, name="x1")

2.2.2 创建多个变量

x = MODEL.addVars(*indexes, lb=0, ub=gurobipy.GRB.INFINITY, vtype=gurobipy.GRB.CONTINUOUS, name="")

x = MODEL.addVars(3, 4, 5, vtype=gurobipy.GRB.BINARY, name="C") # 创建 3*4*5 个变量,使用 x[1,2,3] 进行访问
# lb,ub,vtype 可以单独设置(同样维度数据),也可以全部设置(单个值)
# 此外,若使用 m.addVars(iterable1,iterable2,iterable3) ,相当于笛卡尔积,参考案例 4.2
# 这种创建方法可以使用通配符命令,能简化代码

2.2.3 添加完变量后需要 MODEL.update() 更新变量空间

2.3 添加目标函数 Model.setObjective() 和 Model.setObjectiveN()

2.3.1 单目标优化

MODEL.setObjective(expression, sense=None)

  • expression: 表达式,可以是一次或二次函数类型
  • sense:求解类型,可以是GRB.MINIMIZEGRB.MAXIMIZE
MODEL.setObjective(8 * x1 + 10 * x2 + 7 * x3 + 6 * x4 + 11 * x5 + 9 * x6, gurobipy.GRB.MINIMIZE)
# 执行完成最优化后,可以通过 MODEL.objVal 获取目标函数值(如果存在的话)

2.3.2 多目标优化(默认最小值)

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

多目标优化案例

# 1. 合成型 ######################################################
# Obj1 = x + y          weight = 1
# Obj2 = x - 5 * y      weight = -2
# MODEL.setObjectiveN(x + y, index=0, weight=1, name='obj1')
# MODEL.setObjectiveN(x -5 * y, index=1, weight=-2, name='obj2')
# 即转化为:(x + y) - 2 * (x - 5 * y) = - x + 11 * y
​
# 2. 分层优化型(目标约束时使用) #####################################
# Obj1 = x + y          priority = 5
# Obj2 = x - 5 * y      priority = 1
# MODEL.setObjectiveN(x + y, index=0, priority=5, name='obj1')
# MODEL.setObjectiveN(x -5 * y, index=1, priority=1, name='obj2')
# 即转化为:先优化 Obj1,再优化 Obj2(按照 priority 的大小关系)​
# 3. 混合优化型 ##################################################
# MODEL.setObjectiveN(x + y, index=0, weight=1, priority=5, name='obj1')
# MODEL.setObjectiveN(x -5 * y, index=1, weight=-2, priority=1, name='obj2')
# 则 先优化 Obj1 再优化 Obj2 最后相加作为目标值​
# 4. 执行最优化结束后,获取目标函数值  ###############################
# MODEL.setParam(gurobipy.GRB.Param.ObjNumber, i)   # 第 i 个目标
# print(MODEL.ObjNVal)  # 打印第 i 个值

2.4 添加约束条件 Model.addConstr() 和 Model.addConstrs()

2.4.1 创建一个常规一次/二次/等式约束

MODEL.addConstr(expression, name="")

  • expression: 布尔表达式,可以是一次或二次函数类型
  • name: 约束式的名称

使用方法:

MODEL.addConstr(12 * x1 + 9 * x2 + 25 * x3 + 20 * x4 + 17 * x5 + 13 * x6 >= 60, "c0")
# 注意,此处是调用 c 库实现的,若有 a < b < c,只能拆开写成 a < b,和 b < c

2.4.2 创建多个常规一次/二次/等式约束

MODEL.addConstrs(expressions, name="")

addConstrs 用于添加多个约束条件,参数与 addConstr 类似,最大的优势是可以将外层的 for 循环转化为内部迭代器形式
∑ j = 0 7 x i j ≤ 1 , ∀ i = 0 , 1 , ⋯ , 19 x i j = 0 or  1 \begin{aligned} \sum_{j=0}^{7} x_{i j} \leq 1, \forall i=0,1, \cdots, 19 \\ x_{i j}=0 & \text { or } 1 \end{aligned} j=0∑7​xij​≤1,∀i=0,1,⋯,19xij​=0​ or 1​

x = MODEL.addVars(20, 8, vtype=gurobipy.GRB.BINARY)
# 写法 1
for i in range(20):MODEL.addConstr(x.sum(i, "*") <= 1)
# 写法 2
MODEL.addConstrs(x.sum(i, "*") <= 1 for i in range(20))# 可以将 '*' 理解为切片操作(列表的 list[:])

2.4.3 创建一个范围约束

MODEL.addRange(expression, min_value, max_value, name="")

表达式 min_value<=expression<=max_value 的简写, 但这里的 min_value, max_value 必须是具体的实数值, 不能含有变量

2.4.4 创建一个指示变量约束

MODEL.addGenConstrIndicator(binvar, binval, expression, name="")

指示变量 binvar 的值取 binval 时, 进行约束 expression

案例:
x 1 , x 2 , x 3 = 0 或  ≥ 80 x_{1}, x_{2}, x_{3}=0 \text { 或 } \geq 80 x1​,x2​,x3​=0 或 ≥80

方法一: 构造指示变量 , 则上述约束转化为

80 ⋅ y i ≤ x i ≤ M ⋅ y i ( M 是一个很大的数, 可取  1000 ) 80 \cdot y_{i} \leq x_{i} \leq M \cdot y_{i} \quad(M \text { 是一个很大的数, 可取 } 1000) 80⋅yi​≤xi​≤M⋅yi​(M 是一个很大的数, 可取 1000)

方法二: 转为二次约束, 若矩阵非正定矩阵, 则无法求解

x i ( x i − 80 ) ≥ 0 x_{i}( x_{i}-80) \geq 0 xi​(xi​−80)≥0

案例: 如果生产某一类型汽车 (x[i] > 0), 则至少要生产 80 辆

# %% 方法一
for i in range(3):MODEL.addGenConstrIndicator(y[i + 1], 0, x[i + 1] >= 80)MODEL.addGenConstrIndicator(y[i + 1], 1, x[i + 1] == 0)# 以上代码等价于
for i in range(3):MODEL.addConstr(x[i + 1] >= 80 * y[i + 1])MODEL.addConstr(x[i + 1] <= 1000 * y[i + 1])

2.5 执行最优化 Model.optimize()

MODEL.Params.LogToConsole=True # 显示求解过程
MODEL.Params.MIPGap=0.0001 # 百分比界差
MODEL.Params.TimeLimit=100 # 限制求解时间为 100sMODEL.optimize()

2.6查看模型结果

2.6.1 模型是否取得最优解

MODEL.status == gurobipy.GRB.Status.OPTIMAL

  • True 最优
  • False 非最优, 在TimeLimit模式下, 不能用这个方法判断最优解

2.6.2 单目标优化 —— 查看目标函数值

# 查看单目标规划模型的目标函数值
print("Optimal Objective Value", MODEL.objVal)

2.6.3 多目标优化 —— 查看目标函数值

# 查看多目标规划模型的目标函数值
for i in range(MODEL.NumObj):MODEL.setParam(gurobipy.GRB.Param.ObjNumber, i)print(f"Obj {i+1} = {MODEL.ObjNVal}")

2.6.4 查看变量取值

# 查看变量取值,这个方法用的很少,请看第 4 部分案例
for var in MODEL.getVars():print(f"{var.varName}: {round(var.X, 3)}")

2.6.5 LP 问题灵敏度分析

通过 MODEL.getVars() 得到的变量 var

  • 使用 var.X 可以获取变量值, var.RC 可以获取 Reduced Cost;
  • var.Obj 可以得到在目标函数中的系数
  • var.SAObjLow 可以得到 Allowable Minimize
  • var.SAObjUp 可以得到 Allowable Maximize

通过 MODEL.getConstrs() 得到的约束式 Constr

  • Constr.Slack 可以得到 Slack or Surplus
  • Constr.pi 可以得到 Dual Price
  • Constr.RHS 可以得到约束式右侧常值
  • Constr.SARHSLow 可以得到 Allowable Minimize
  • Constr.SARHSUp 可以得到 Allowable Maximize

3 实例:一般线性规划问题

min ⁡ Z = 8 x 1 + 10 x 2 + 7 x 3 + 6 x 4 + 11 x 5 + 9 x 6 s.t.  12 x 1 + 9 x + 25 x 3 + 20 x 4 + 17 x 5 + 13 x 6 ≥ 60 35 x 1 + 42 x 2 + 18 x 3 + 31 x 4 + 56 x 5 + 49 x 6 ≥ 150 37 x 1 + 53 x 2 + 28 x 3 + 24 x 4 + 29 x 5 + 20 x 6 ≥ 125 0 ≤ x j ≤ 1 , j = 1 , 2 , ⋯ , 6 \begin{array}{ll} \min & Z=8 x_{1}+10 x_{2}+7 x_{3}+6 x_{4}+11 x_{5}+9 x_{6} \\ \text { s.t. } & 12 x_{1}+9 x+25 x_{3}+20 x_{4}+17 x_{5}+13 x_{6} \geq 60 \\ & 35 x_{1}+42 x_{2}+18 x_{3}+31 x_{4}+56 x_{5}+49 x_{6} \geq 150 \\ & 37 x_{1}+53 x_{2}+28 x_{3}+24 x_{4}+29 x_{5}+20 x_{6} \geq 125 \\ & 0 \leq x_{j} \leq 1, j=1,2, \cdots, 6 \end{array} min s.t. ​Z=8x1​+10x2​+7x3​+6x4​+11x5​+9x6​12x1​+9x+25x3​+20x4​+17x5​+13x6​≥6035x1​+42x2​+18x3​+31x4​+56x5​+49x6​≥15037x1​+53x2​+28x3​+24x4​+29x5​+20x6​≥1250≤xj​≤1,j=1,2,⋯,6​

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("Example")# 创建变量
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("Obj:", MODEL.objVal)
for v in MODEL.getVars():print(f"{v.varName}:{round(v.x,3)}")

4、 ★佐佑思维公众号提供更多学习学术服务★ 二维码如下:

Gurobi +Python 高效数学规划及建模实例相关推荐

  1. Python小白的数学建模课-03.线性规划

    线性规划是很多数模培训讲的第一个算法,算法很简单,思想很深刻. 要通过线性规划问题,理解如何学习数学建模.如何选择编程算法. 『Python小白的数学建模课 @ Youcans』带你从数模小白成为国赛 ...

  2. python人工智能项目实例-Python在人工智能中的实例

    自近几年来,人工智能技术越发火热,Python这门最适合用于人工智能项目开发的语言也步入大众视野,越来越多的同学选择成为一名Python工程师.但迈入机器学习与人工智能领域绝非易事,考虑到目前市面上存 ...

  3. Python小白的数学建模课-10.微分方程边值问题

    小白往往听到微分方程就觉得害怕,其实数学建模中的微分方程模型不仅没那么复杂,而且很容易写出高水平的数模论文. 本文介绍微分方程模型边值问题的建模与求解,不涉及算法推导和编程,只探讨如何使用 Pytho ...

  4. Python小白的数学建模课-06.固定费用问题

    Python 实例介绍固定费用问题的建模与求解. 学习 PuLP工具包中处理复杂问题的快捷使用方式. 『Python小白的数学建模课 @ Youcans』带你从数模小白成为国赛达人. 前文讲到几种典型 ...

  5. Python小白的数学建模课-05.0-1规划

    0-1 规划不仅是数模竞赛中的常见题型,也具有重要的现实意义. 双十一促销中网购平台要求二选一,就是互斥的决策问题,可以用 0-1规划建模. 小白学习 0-1 规划,首先要学会识别 0-1规划,学习将 ...

  6. Python小白的数学建模课-02.数据导入

    数据导入是所有数模编程的第一步,比你想象的更重要. 先要学会一种未必最佳,但是通用.安全.简单.好学的方法. 『Python小白的数学建模课 @ Youcans』 带你从数模小白成为国赛达人. 1. ...

  7. Python小白的数学建模课-01.新手必读

    Python 完全可以满足数学建模的需要. Python 是数学建模的最佳选择之一,而且在其它工作中也无所不能. 『Python小白的数学建模课 @ Youcans』 带你从数模小白成为国赛达人. 欢 ...

  8. Python小白的数学建模课-09.微分方程模型

    小白往往听到微分方程就觉得害怕,其实数学建模中的微分方程模型不仅没那么复杂,而且很容易写出高水平的数模论文. 本文介绍微分方程模型的建模与求解,通过常微分方程.常微分方程组.高阶常微分方程 3个案例手 ...

  9. Python小白的数学建模课-09 微分方程模型

    1. 微分方程 1.1 基本概念 微分方程是描述系统的状态随时间和空间演化的数学工具.物理中许多涉及变力的运动学.动力学问题,如空气的阻力为速度函数的落体运动等问题,很多可以用微分方程求解.微分方程在 ...

最新文章

  1. php挖洞提权,记一次渗透挖洞提权实战
  2. python中导入包中的__init__文件夹的一个重要作用(去年对文件名的导入)
  3. c语言向自定数组_C语言一维数组的定义和引用
  4. Win下执行Swing程序的BAT文件 和 Linux下执行Swing程序的SH文件
  5. 数据库去重查询问题详解
  6. kangle支不支持PHP_【转载】PHP调用kangle的API
  7. hashmap扩容线程安全问题_HashMap线程不安全的体现
  8. jQuery使用ajax错误的重复发送请求的解决办法
  9. 随想录(编写简单资源管理代码)
  10. 赛车游戏代码大全html,赛车游戏代码
  11. vscode中出现 Statements must be separated by newlines or semicolons 问题的解决方法之一
  12. java导出图片到excel_POI:将图片导出到Excel
  13. 微信小程序被投诉怎么办?小妙招教给你
  14. 关于TypeScript开发的6个小技巧
  15. vi设计管理手册的体系
  16. 计算机广东大专院校排名2018,重磅!广东85所专科院校官方排名刚刚出炉,这所高职回归第一!...
  17. Criterion 用法
  18. 微信公众号开发 自定义分享 从前台到Java后台 调用微信JS接口分享朋友圈
  19. Excel日期连接后变数字
  20. 汇编语言(王爽第三版) 实验5

热门文章

  1. MyBatis的缓存机制详解
  2. HyperWorks13安装教程
  3. 浙里办单点登录-PHP-TP5-轻松上手
  4. 黄金3:雨露均沾-不要让你的线程在竞争中被“饿死”
  5. 【C语言】算法学习·回溯算法
  6. oracle的delimiter,Oracle Q-quote delimiter
  7. 降噪耳机排行榜10强,值得入手的四款降噪耳机分享
  8. 数据查询(3)-复杂查询
  9. 从两通客服电话看支付宝和快钱
  10. WebGoat攻略 for Mac(3)