Python数模笔记-PuLP库(2)线性规划进阶
1、基于字典的创建规划问题
上篇中介绍了使用 LpVariable 对逐一定义每个决策变量,设定名称、类型和上下界,类似地对约束条件也需要逐一设置模型参数。在大规模的规划问题中,这样逐个定义变量和设置模型参数非常繁琐,效率很低。Pulp 库提供了一种快捷方式,可以结合 Python语言的循环和容器,使用字典来创建问题。
(1)使用快捷方法建立一个规划问题,可以用字典类型(dict) 建立多个变量,例如:
name = ['废料1', '废料2', '废料3', '废料4', '镍', '铬', '钼']
# A dictionary of the costs of each of the Ingredients is created
mass = pulp.LpVariable.dicts("原料", material, lowBound=0, cat='Continuous')
(2)使用字典类型(dict) 设置目标函数和约束条件的参数,例如:
cost = {
'废料1': 16,
'废料2': 10,
'废料3': 8,
'废料4': 9,
'镍': 48,
'铬': 60,
'钼': 53}
(3)使用 遍历循环结构 设置目标函数和约束条件,例如:
AlloyModel += pulp.lpSum([cost[item] * mass[item] for item in material]), "总生产成本"
AlloyModel += pulp.lpSum([mass[item] for item in material]) == 1000, "质量约束"
详细用法参见下节例程。
=== 关注 Youcans,分享更多原创系列 https://www.cnblogs.com/youcans/ ===
2、线性规划问题案例
本篇以合金钢材生产投料问题为例,分析基于列表和字典创建问题的快捷方法。
问题描述:
某钢铁厂通过熔炼回收的金属废料并添加一定新料的方法生产满足化学成分要求的合金,计划生产1000千克的合金。
所有金属废料的主要成分是铁,不同金属废料还含有各种微量元素。
金属废料、新料的各组分含量占比、可用数量和单位成本如下表所示。生成合金中各组分的含量要求,也如表中所示。
问如何安排投料比例,在满足合金组分含量要求的条件下的材料成本最小?
| 材料 | 碳 | 镍 | 铬 | 钼 | 可用量 | 成本 |
|---|---|---|---|---|---|---|
| 废料1 | 0.80 | 18.0 | 12.0 | 0.0 | 75 | 16 |
| 废料2 | 0.70 | 3.2 | 1.1 | 0.1 | 250 | 10 |
| 废料3 | 0.85 | 0 | 0 | 0 | 不限 | 8 |
| 废料4 | 0.40 | 0 | 0 | 0 | 不限 | 9 |
| 镍 | 0 | 100 | 0 | 0 | 不限 | 48 |
| 铬 | 0 | 0 | 100 | 0 | 不限 | 60 |
| 钼 | 0 | 0 | 0 | 100 | 不限 | 53 |
| 合金下限 | 0.65 | 3.0 | 1.0 | 1.1 | / | / |
| 合金上限 | 0.75 | 3.5 | 1.2 | 1.3 | / | / |
3、建立模型
(1)决策变量
x1:废料 1 用量(千克)
x2:废料 2 用量(千克)
x3:废料 3 用量(千克)
x4:废料 4 用量(千克)
x5:原料镍 用量(千克)
x6:原料铬 用量(千克)
x7:原料钼 用量(千克)
(2)目标函数:
min cost = 16*x1 + 10*x2 + 8*x3 + 9*x4 + 48*x5 + 60*x6 + 53*x7
(3)约束条件:
0.8*x1 + 0.7*x2 + 0.85*x3 + 0.40*x4 >= 0.65*1000
0.8*x1 + 0.7*x2 + 0.85*x3 + 0.40*x4 <= 0.75*1000
18.0*x1 + 3.2*x2 + 100.0*x5 >= 3.0*1000
18.0*x1 + 3.2*x2 + 100.0*x5 <= 3.5*1000
12.0*x1 + 1.1*x2 + 100.0*x6 >= 1.0*1000
12.0*x1 + 1.1*x2 + 100.0*x6 >= 1.2*1000
0.1*x2 + 100.0*x7 >= 1.1*1000
0.1*x2 + 100.0*x7 >= 1.3*1000
(4)变量取值范围:
xi >= 0, i=1,2,...7
x1 <= 75, x2 <= 250
4、PuLP 程序 1:使用 LpVariable 逐一定义变量
本程序与上篇的方法相同,使用 LpVariable 逐一定义变量。完整的程序代码如下:
import pulp # 导入 pulp库
# 1.建立优化问题 AlloyLP: 求最小值(LpMinimize)
AlloyLP = pulp.LpProblem("合金生产材料优化", sense=pulp.LpMinimize) # 定义问题,求最小值
# 2.定义决策变量 x1~x7
x1 = pulp.LpVariable('废料1#', lowBound=0, upBound=75.0, cat='Continuous') # 定义 x1
x2 = pulp.LpVariable('废料2#', lowBound=0, upBound=250., cat='Continuous') # 定义 x2
x3 = pulp.LpVariable('废料3#', lowBound=0, cat='Continuous') # 定义 x3
x4 = pulp.LpVariable('废料4#', lowBound=0, cat='Continuous') # 定义 x4
x5 = pulp.LpVariable('原料镍', lowBound=0, cat='Continuous') # 定义 x5
x6 = pulp.LpVariable('原料铬', lowBound=0, cat='Continuous') # 定义 x6
x7 = pulp.LpVariable('原料钼', lowBound=0, cat='Continuous') # 定义 x7
# 3.定义目标函数 cost
AlloyLP += (16*x1 + 10*x2 + 8*x3 + 9*x4 + 48*x5 + 60*x6 + 53*x7) # 投料成本
# 4.设置约束条件
AlloyLP += (x1 + x2 + x3 + x4 + x5 + x6 + x7 == 1000) # 等式约束
AlloyLP += (0.8*x1 + 0.7*x2 + 0.85*x3 + 0.4*x4 >= 0.65*1000) # 不等式约束
AlloyLP += (0.8*x1 + 0.7*x2 + 0.85*x3 + 0.4*x4 <= 0.75*1000) # 不等式约束
AlloyLP += (18.0*x1 + 3.2*x2 + 100.0*x5 >= 3.0*1000) # 不等式约束
AlloyLP += (18.0*x1 + 3.2*x2 + 100.0*x5 <= 3.5*1000) # 不等式约束
AlloyLP += (12.0*x1 + 1.1*x2 + 100.0*x6 >= 1.0*1000) # 不等式约束
AlloyLP += (12.0*x1 + 1.1*x2 + 100.0*x6 <= 1.2*1000) # 不等式约束
AlloyLP += (0.1*x2 + 100.0*x7 >= 1.1*1000) # 不等式约束
AlloyLP += (0.1*x2 + 100.0*x7 <= 1.3*1000) # 不等式约束
AlloyLP += (x1 + x2 + x3 + x4 + x5 + x6 + x7 == 1000) # 等式约束
# 5.求解线性规划问题
AlloyLP.solve()
# 6.输出优化结果
#=== 关注 Youcans,分享更多原创系列 https://www.cnblogs.com/youcans/ ===
print(AlloyLP) # 输出问题设定参数和条件
# print("求解状态:", pulp.LpStatus[AlloyLP.status]) # 输出求解状态
for v in AlloyLP.variables():
print(v.name, " = ", v.varValue) # 输出每个变量的最优值
print("最小材料成本 = ", pulp.value(AlloyLP.objective)) # 输出最优解的目标函数值
5、PuLP 程序 2:使用 dict 定义决策变量和约束条件
本程序使用 dict 定义变量、目标函数和约束条件参数,便于复杂问题的参数设定。
import pulp # 导入 pulp库
# 1. 建立问题
AlloyModel = pulp.LpProblem("钢材生产问题", pulp.LpMinimize)
# 2. 建立变量
material = ['废料1', '废料2', '废料3', '废料4', '镍', '铬', '钼']
mass = pulp.LpVariable.dicts("原料", material, lowBound=0, cat='Continuous')
# 3. 设置目标函数
cost = {
'废料1': 16,
'废料2': 10,
'废料3': 8,
'废料4': 9,
'镍': 48,
'铬': 60,
'钼': 53}
AlloyModel += pulp.lpSum([cost[item] * mass[item] for item in material]), "总生产成本"
# # 4. 施加约束
carbonPercent = {
'废料1': 0.8,
'废料2': 0.7,
'废料3': 0.85,
'废料4': 0.4,
'镍': 0,
'铬': 0,
'钼': 0}
NiPercent = {
'废料1': 18,
'废料2': 3.2,
'废料3': 0,
'废料4': 0,
'镍': 100,
'铬': 0,
'钼': 0}
CrPercent = {
'废料1': 12,
'废料2': 1.1,
'废料3': 0,
'废料4': 0,
'镍': 0,
'铬': 100,
'钼': 0}
MoPercent = {
'废料1': 0,
'废料2': 0.1,
'废料3': 0,
'废料4': 0,
'镍': 0,
'铬': 0,
'钼': 100}
AlloyModel += pulp.lpSum([mass[item] for item in material]) == 1000, "质量约束"
AlloyModel += pulp.lpSum([carbonPercent[item] * mass[item] for item in material]) >= 0.65*1000, "碳最小占比"
AlloyModel += pulp.lpSum([carbonPercent[item] * mass[item] for item in material]) <= 0.75*1000, "碳最大占比"
AlloyModel += pulp.lpSum([NiPercent[item] * mass[item] for item in material]) >= 3.0*1000, "镍最小占比"
AlloyModel += pulp.lpSum([NiPercent[item] * mass[item] for item in material]) <= 3.5*1000, "镍最大占比"
AlloyModel += pulp.lpSum([CrPercent[item] * mass[item] for item in material]) >= 1.0*1000, "铬最小占比"
AlloyModel += pulp.lpSum([CrPercent[item] * mass[item] for item in material]) <= 1.2*1000, "铬最大占比"
AlloyModel += pulp.lpSum([MoPercent[item] * mass[item] for item in material]) >= 1.1*1000, "钼最小占比"
AlloyModel += pulp.lpSum([MoPercent[item] * mass[item] for item in material]) <= 1.3*1000, "钼最大占比"
AlloyModel += mass['废料1'] <= 75, "废料1可用量"
AlloyModel += mass['废料2'] <= 250, "废料2可用量"
# 5. 求解
AlloyModel.solve()
# 6. 打印结果
print(AlloyModel) # 输出问题设定参数和条件
print("优化状态:", pulp.LpStatus[AlloyModel.status])
for v in AlloyModel.variables():
print(v.name, "=", v.varValue)
print("最优总成本 = ", pulp.value(AlloyModel.objective))
3、Python程序和运行结果
程序 1 和程序 2 的运行结果完全相同,结果如下:
Welcome to the CBC MILP Solver
Version: 2.9.0
Build Date: Feb 12 2015
钢材生产问题:
MINIMIZE
16*原料_废料1 + 10*原料_废料2 + 8*原料_废料3 + 9*原料_废料4 + 53*原料_钼 + 60*原料_铬 + 48*原料_镍 + 0
SUBJECT TO
质量约束: 原料_废料1 + 原料_废料2 + 原料_废料3 + 原料_废料4 + 原料_钼 + 原料_铬 + 原料_镍 = 1000
碳最小占比: 0.8 原料_废料1 + 0.7 原料_废料2 + 0.85 原料_废料3 + 0.4 原料_废料4 >= 650
碳最大占比: 0.8 原料_废料1 + 0.7 原料_废料2 + 0.85 原料_废料3 + 0.4 原料_废料4 <= 750
镍最小占比: 18 原料_废料1 + 3.2 原料_废料2 + 100 原料_镍 >= 3000
镍最大占比: 18 原料_废料1 + 3.2 原料_废料2 + 100 原料_镍 <= 3500
铬最小占比: 12 原料_废料1 + 1.1 原料_废料2 + 100 原料_铬 >= 1000
铬最大占比: 12 原料_废料1 + 1.1 原料_废料2 + 100 原料_铬 <= 1200
钼最小占比: 0.1 原料_废料2 + 100 原料_钼 >= 1100
钼最大占比: 0.1 原料_废料2 + 100 原料_钼 <= 1300
废料1可用量: 原料_废料1 <= 75
废料2可用量: 原料_废料2 <= 250
VARIABLES
原料_废料1 Continuous
原料_废料2 Continuous
原料_废料3 Continuous
原料_废料4 Continuous
原料_钼 Continuous
原料_铬 Continuous
原料_镍 Continuous
优化状态: Optimal
原料_废料1 = 75.0
原料_废料2 = 90.909091
原料_废料3 = 672.28283
原料_废料4 = 137.30808
原料_钼 = 10.909091
原料_铬 = 0.0
原料_镍 = 13.590909
最优总成本 = 9953.671725000002
=== 关注 Youcans,分享更多原创系列 https://www.cnblogs.com/youcans/ ===
版权说明:
原创作品
Copyright 2021 YouCans, XUPT
Crated:2021-04-28
Python数模笔记-PuLP库(2)线性规划进阶的更多相关文章
- Python数模笔记-PuLP库(1)线性规划入门
1.什么是线性规划 线性规划(Linear programming),在线性等式或不等式约束条件下求解线性目标函数的极值问题,常用于解决资源分配.生产调度和混合问题.例如: max fx = 2*x1 ...
- Python数模笔记-Scipy库(1)线性规划问题
1.最优化问题建模 最优化问题的三要素是决策变量.目标函数和约束条件. (1)分析影响结果的因素是什么,确定决策变量 (2)决策变量与优化目标的关系是什么,确定目标函数 (3)决策变量所受的限制条件是 ...
- Python数模笔记-StatsModels 统计回归(4)可视化
1.如何认识可视化? 图形总是比数据更加醒目.直观.解决统计回归问题,无论在分析问题的过程中,还是在结果的呈现和发表时,都需要可视化工具的帮助和支持. 需要指出的是,虽然不同绘图工具包的功能.效果会有 ...
- Python数模笔记-StatsModels 统计回归(1)简介
1.关于 StatsModels statsmodels(http://www.statsmodels.org)是一个Python库,用于拟合多种统计模型,执行统计测试以及数据探索和可视化. 2.文档 ...
- Python数模笔记-NetworkX(3)条件最短路径
1.带有条件约束的最短路径问题 最短路径问题是图论中求两个顶点之间的最短路径问题,通常是求最短加权路径. 条件最短路径,指带有约束条件.限制条件的最短路径.例如,顶点约束,包括必经点或禁止点的限制:边 ...
- Python数模笔记-Sklearn(1) 介绍
1.SKlearn 是什么 Sklearn(全称 SciKit-Learn),是基于 Python 语言的机器学习工具包. Sklearn 主要用Python编写,建立在 Numpy.Scipy.Pa ...
- Python数模笔记-(1)NetworkX 图的操作
1.NetworkX 图论与网络工具包 NetworkX 是基于 Python 语言的图论与复杂网络工具包,用于创建.操作和研究复杂网络的结构.动力学和功能. NetworkX 可以以标准和非标准的数 ...
- Python数模笔记-Sklearn(4)线性回归
1.什么是线性回归? 回归分析(Regression analysis)是一种统计分析方法,研究自变量和因变量之间的定量关系.回归分析不仅包括建立数学模型并估计模型参数,检验数学模型的可信度,也包括利 ...
- Python数模笔记-Sklearn(2)样本聚类分析
1.分类的分类 分类的分类?没错,分类也有不同的种类,而且在数学建模.机器学习领域常常被混淆. 首先我们谈谈有监督学习(Supervised learning)和无监督学习(Unsupervised ...
随机推荐
- Spring Security框架中踢人下线技术探索
1.背景 在某次项目的开发中,使用到了Spring Security权限框架进行后端权限开发的权限校验,底层集成Spring Session组件,非常方便的集成Redis进行分布式Session的会话 ...
- ElementPlusViteStarterPnpm版本
1 起因 由于最近Vite升级了2.x版本,项目中需要改动的东西有点多,本来想基于官方给出的starter重做,但是又看到了一个叫pnpm的仓库,构建速度会比原生npm/yarn快两倍以上: 因此模仿 ...
- Jenkins 分布式和并发构建
1. 分布式构建 1.1 添加 linux 节点 1.2 添加 windows 节点 2. 并发构建 2.1 原理 2.2 示例:分别用 chrome/IE/Firefox 并行测试 1. 分布式构建 ...
- Python 元编程 - 装饰器
Python 中提供了一个叫装饰器的特性,用于在不改变原始对象的情况下,增加新功能或行为. 这也属于 Python "元编程" 的一部分,在编译时一个对象去试图修改另一个对象的信息 ...
- OAuth 2.0、OIDC 原理
OAuth 目录 OAuth 什么是 OAuth? 为什么是 OAuth? SAML OAuth 和 API OAuth 主要组件 OAuth 作用域 OAuth 参与者 OAuth 令牌 OAuth ...
- php判断请求类型(ajax|get|post|cli)
php判断请求类型,可以通过 $_SERVER 相关的参数来实现, 这个很在对某些请求代码复用里面很常用.具体代码如下: /** *@todo: 判断是否为post */ if(!function_e ...
- ARM汇编中的:比较指令--CMN / CMP / TEQ / TST
1. 简介 CMP / CMN : 算术指令 TEQ / TST : 逻辑指令 它们总是会影响CPSR条件标志位. APSR(CPSR)与condition的关系图: 2. CMN -- 比 ...
- 一枚Android "短信小偷" 病毒的分析
一.样本简介 样本来自于吾爱破解论坛链接地址为http://www.52pojie.cn/thread-410238-1-1.html,样本不是很复杂有空就分析了一下.Android病毒样本还是很有意 ...
- POJ1236 强连通 (缩点后度数的应用)
题意: 一些学校有一个发送消息的体系,现在给你一些可以直接发送消息的一些关系(单向)然后有两个问题 (1) 问你至少向多少个学校发送消息可以让所有的学校都得到消息 (2) 问至少加多少条边 ...
- Python中os模块、csv模块和xlrd模块的使用
目录 os模块的使用 open("test.txt","mode") 读取文件中的内容 f.read() f.readline(size) f.readline ...