整数线性规划——pulp指南

news2024/12/25 14:03:00

整数线性规划——pulp指南

PuLP是一个用Python编写的线性规划建模工具。PuLP可以生成MPS或LP文件,并调用GLPK、COIN-OR CLP/CBC、CPLEX、GUROBI、MOSEK、XPRESS、CHOCO、MIPCL、HiGHS、SCIP/FSCIP等求解线性问题。

官方文档地址:https://coin-or.github.io/pulp/index.html

线性规划的标准表示如下:

(LP) min ⁡ c T x , s . t .   A x ≤ b , x ∈ R + n \text{(LP)}\quad\begin{aligned} &\min c^Tx,\\ &s.t.\ Ax\le b,\\ &\qquad x\in \R_+^n \end{aligned} (LP)mincTx,s.t. Axb,xR+n

一、引入

使用pip install pulp安装pulp。

from pulp import *

可以使用LpVariable() 创建新的变量,例如创建变量 0 ≤ x ≤ 3 0\le x\le 3 0x3

x = LpVariable("x", 0, 3)

创建变量 0 ≤ y ≤ 1 0\le y\le 1 0y1

y = LpVariable("y", 0, 1)

使用LpProblem()创建新的问题,比如说创建名为myProblem的线性规划问题:

prob = LpProblem("myProblem", LpMinimize)

将变量组合成表达式和约束条件,然后将它们添加到问题中:

prob += x + y <= 2

如果添加一个表达式(而非约束),它将变成目标函数:

prob += -4*x + y

使用默认求解器进行求解:

status = prob.solve()

展示解的状态:

LpStatus[status]
'Optimal'

查看具体的值:

print(value(x))
print(value(y))
2.0
0.0

二、配置求解器

PuLP通常有多种连接求解器的方式。根据连接方式的不同,配置连接的方法也会有所不同。我们可以将集成总结为两大类:

  1. 使用求解器的命令行界面。

  2. 使用求解器的Python库。

并非所有求解器都有Python库,但大多数都有命令行界面。如果求解器API的名称以CMD结尾(例如PULP_CBC_CMD、CPLEX_CMD、GUROBI_CMD等),那么它就是命令行,否则是python库。

这里我安装cplex,可以前往IBM官网进行申请安装:https://www.ibm.com/analytics/cplex-optimizer。

配置路径如下:

# 这里需要换成自己电脑上cplex.exe所在的地址
path_to_cplex = r'D:\software\cplex\cplex\bin\x64_win64\cplex.exe'
import pulp as pl
model = pl.LpProblem("Example", pl.LpMinimize)
solver = pl.CPLEX_CMD(path=path_to_cplex)
_var = pl.LpVariable('a')
_var2 = pl.LpVariable('a2')
model += _var + _var2 == 1
result = model.solve(solver)

配置一次以后便不用再配置。

import pulp as pl
model = pl.LpProblem("Example", pl.LpMinimize)
solver = pl.CPLEX_CMD()
_var = pl.LpVariable('a')
_var2 = pl.LpVariable('a2')
model += _var + _var2 == 1
result = model.solve(solver)
print(result)
1

三、案例学习——猫粮问题

问题描述

Uncle Ben’s希望以尽可能低的成本生产他们的猫粮产品,同时确保它们符合罐头上显示的营养分析要求。因此,他们希望在仍然满足营养标准的情况下改变使用每种成分的数量(主要成分包括鸡肉、牛肉、羊肉、大米、小麦和明胶)。

在这里插入图片描述

鸡肉、牛肉和羊肉的成本分别为0.013美元、0.008美元和0.010美元,而大米、小麦和明胶的成本分别为0.002美元、0.005美元和0.001美元。(所有成本均为每克。)对于这个练习,我们将忽略维生素和矿物质成分。(这些成本可能非常小。)

每种成分对最终产品中蛋白质、脂肪、纤维和盐的总重量都有贡献。每克成分的贡献(以克为单位)如下表所示:

StuffProteinFatFibreSalt
Chicken0.1000.0800.0010.002
Beef0.2000.1000.0050.005
Mutton0.1500.1100.0030.007
Rice0.0000.0100.1000.002
Wheat bran0.0400.0100.1500.008
Gel0.0000.0000.0000.000

建模表示

确定决策变量

假设Whiskas想要用两种成分制作他们的猫食:鸡肉和牛肉。首先定义我们的决策变量:

x 1 = 一罐猫粮中所用鸡肉的百分比 x 2 = 一罐猫粮中所用牛肉的百分比 x_1=一罐猫粮中所用鸡肉的百分比\\ x_2 =一罐猫粮中所用牛肉的百分比 x1=一罐猫粮中所用鸡肉的百分比x2=一罐猫粮中所用牛肉的百分比

这些变量必须大于零。

制定目标函数

目标函数变为:

min ⁡ 0.013 x 1 + 0.008 x 2 \min 0.013x_1+0.008x_2 min0.013x1+0.008x2

限制

变量必须加起来等于100,并且满足营养需求:

1.000 x 1 + 1.000 x 2 = 100.0 0.100 x 1 + 0.200 x 2 ≥ 8.0 0.080 x 1 + 0.100 x 2 ≥ 6.0 0.001 x 1 + 0.005 x 2 ≤ 2.0 0.002 x 1 + 0.005 x 2 ≤ 0.4 \begin{aligned} 1.000x_1&+1.000x_2=100.0\\ 0.100x_1&+0.200x_2\ge 8.0\\ 0.080x_1&+0.100x_2\ge 6.0\\ 0.001x_1&+0.005x_2\le 2.0\\ 0.002x_1&+0.005x_2\le 0.4 \end{aligned} 1.000x10.100x10.080x10.001x10.002x1+1.000x2=100.0+0.200x28.0+0.100x26.0+0.005x22.0+0.005x20.4

python实现

引入库:

from pulp import *

使用LpProblem函数定义名为prob的变量。它有两个参数,第一个是此问题的任意名称(作为字符串),第二个参数取决于要解决的LP类型,可以是LpMinimize或LpMaximize:

prob = LpProblem("WhiskasModel", LpMinimize)

使用 LpVariable 类创建问题变量 x1x2 。它有四个参数,第一个是表示此变量的任意名称,第二个是此变量的下限,第三个是上限,第四个是数据类型(离散或连续)。第四个参数的选项为LpContinuousLpInteger,其默认值为LpContinuous。如果我们正在建模要生产的罐数,我们需要输入LpInteger,因为它是离散数据。边界可以直接输入为数字,或者为 None 表示没有边界(即正无穷或负无穷),默认值为 None。创建适用于本问题的两个变量:

# 本问题中的鸡肉和牛肉变量
x1 = LpVariable("ChickenPercent",0 , None, LpInteger)
x2 = LpVariable("BeefPercent",0 , None, LpInteger)

添加目标函数:

# 首先添加目标函数
prob += 0.013 * x1 + 0.008 * x2, "每罐猫粮的成本价格"

添加限制条件:

# The five constraints are entered
prob += x1 + x2 == 100, "百分比之和"
prob += 0.100 * x1 + 0.200 * x2 >= 8.0, "蛋白质需求"
prob += 0.080 * x1 + 0.100 * x2 >= 6.0, "脂肪需求"
prob += 0.001 * x1 + 0.005 * x2 <= 2.0, "纤维需求"
prob += 0.002 * x1 + 0.005 * x2 <= 0.4, "盐分需求"

使用 writeLP() 函数将这些信息复制到一个 .lp 文件中,该文件位于你的代码块运行的目录中。一旦代码成功运行,可以使用文本编辑器打开这个 .lp 文件,看看上面的步骤都在做什么:

# 将问题数据写入.lp文件中
prob.writeLP('WhiskasModel.lp')
[BeefPercent, ChickenPercent]

LP问题是使用PuLP选择的求解器来解决的,在这种情况下,solve() 后面的输入括号为空,但是它们可以用来指定要使用的求解器(例如,prob.solve(CPLEX())):

prob.solve(CPLEX())
1

输出求解结果,结果可能是 “Not Solved”, “Infeasible”, “Unbounded”, “Undefined” 或者 “Optimal”:

print("Status:", LpStatus[prob.status])
Status: Optimal

查看各个变量的值:

for v in prob.variables():
    print(v.name, "=", v.varValue)
BeefPercent = 66.0
ChickenPercent = 34.0

输出目标函数的值:

print("每罐猫粮的原材料成本为:", value(prob.objective))
每罐猫粮的原材料成本为: 0.97

完整公式

现在我们将使用所有变量完全公式化问题。虽然可以在上面的方法中加入一些内容将其实现为Python,但我们将看到一种更好的方法,它不会混合问题数据和公式化。这将使更改其他测试的任何问题数据变得更容易。我们将以代数方式定义问题的方式开始:

  1. 确定决策变量,决策变量是我们在罐中包含的不同成分的百分比。由于罐子重100g,这些百分比也代表每种成分包含的克数。请注意,这些百分比必须介于0和100之间。

    x 1 = 一罐猫粮中所用鸡肉的百分比 x 2 = 一罐猫粮中所用牛肉的百分比 x 3 = 一罐猫粮中所用羊肉的百分比 x 4 = 一罐猫粮中所用米饭的百分比 x 5 = 一罐猫粮中所用麦麸的百分比 x 6 = 一罐猫粮中所用凝胶的百分比 x_1=一罐猫粮中所用鸡肉的百分比\\ x_2=一罐猫粮中所用牛肉的百分比\\ x_3=一罐猫粮中所用羊肉的百分比\\ x_4=一罐猫粮中所用米饭的百分比\\ x_5=一罐猫粮中所用麦麸的百分比\\ x_6=一罐猫粮中所用凝胶的百分比 x1=一罐猫粮中所用鸡肉的百分比x2=一罐猫粮中所用牛肉的百分比x3=一罐猫粮中所用羊肉的百分比x4=一罐猫粮中所用米饭的百分比x5=一罐猫粮中所用麦麸的百分比x6=一罐猫粮中所用凝胶的百分比

  2. 制定目标函数。对于Whiskas猫食品问题,目标是最小化每罐猫食品成分的总成本。

    min ⁡ 0.013 x 1 + 0.008 x 2 + 0.010 x 3 + 0.002 x 4 + 0.005 x 5 + 0.001 x 6 \min 0.013x_1+0.008x_2+0.010x_3+0.002x_4+0.005x_5+0.001x_6 min0.013x1+0.008x2+0.010x3+0.002x4+0.005x5+0.001x6

  3. 制定约束条件。Whiskas猫食品问题的约束条件是:

    • 百分比总和必须占整个罐子(= 100%)。

    • 满足规定的营养分析要求。

    “整罐”的约束是:

    x 1 + x 2 + x 3 + x 4 + x 5 + x 6 = 100 x_1+x_2+x_3+x_4+x_5+x_6=100 x1+x2+x3+x4+x5+x6=100

    为了满足营养分析要求,我们需要每100g至少8g蛋白质,6g脂肪,但不超过2g纤维和0.4g盐。为了制定这些约束条件,我们利用以前的每种成分贡献表。这使我们能够制定有关来自成分的蛋白质,脂肪,纤维和盐总贡献的以下约束条件:
    0.100 x 1 + 0.200 x 2 + 0.150 x 3 + 0.000 x 4 + 0.040 x 5 + 0.0 x 6 ≥ 8.0 0.080 x 1 + 0.100 x 2 + 0.110 x 3 + 0.010 x 4 + 0.010 x 5 + 0.0 x 6 ≥ 6.0 0.001 x 1 + 0.005 x 2 + 0.003 x 3 + 0.100 x 4 + 0.150 x 5 + 0.0 x 6 ≤ 2.0 0.002 x 1 + 0.005 x 2 + 0.007 x 3 + 0.002 x 4 + 0.008 x 5 + 0.0 x 6 ≤ 0.4 \begin{aligned} 0.100x_1&+0.200x_2+0.150x_3+0.000x_4+0.040x_5+0.0x_6≥8.0\\ 0.080x_1&+0.100x_2+0.110x_3+0.010x_4+0.010x_5+0.0x_6≥6.0\\ 0.001x_1&+0.005x_2+0.003x_3+0.100x_4+0.150x_5+0.0x_6≤2.0\\ 0.002x_1&+0.005x_2+0.007x_3+0.002x_4+0.008x_5+0.0x_6≤0.4 \end{aligned} 0.100x10.080x10.001x10.002x1+0.200x2+0.150x3+0.000x4+0.040x5+0.0x68.0+0.100x2+0.110x3+0.010x4+0.010x5+0.0x66.0+0.005x2+0.003x3+0.100x4+0.150x5+0.0x62.0+0.005x2+0.007x3+0.002x4+0.008x5+0.0x60.4

python实现

from pulp import *
# 原材料
Ingredients = ["CHICKEN", "BEEF", "MUTTON", "RICE", "WHEAT", "GEL"]

# 成本字典
costs = {
    "CHICKEN": 0.013,
    "BEEF": 0.008,
    "MUTTON": 0.010,
    "RICE": 0.002,
    "WHEAT": 0.005,
    "GEL": 0.001,
}

# 蛋白质字典
proteinPercent = {
    "CHICKEN": 0.100,
    "BEEF": 0.200,
    "MUTTON": 0.150,
    "RICE": 0.000,
    "WHEAT": 0.040,
    "GEL": 0.000,
}

# 脂肪字典
fatPercent = {
    "CHICKEN": 0.080,
    "BEEF": 0.100,
    "MUTTON": 0.110,
    "RICE": 0.010,
    "WHEAT": 0.010,
    "GEL": 0.000,
}

# 纤维字典
fibrePercent = {
    "CHICKEN": 0.001,
    "BEEF": 0.005,
    "MUTTON": 0.003,
    "RICE": 0.100,
    "WHEAT": 0.150,
    "GEL": 0.000,
}

# 盐分字典
saltPercent = {
    "CHICKEN": 0.002,
    "BEEF": 0.005,
    "MUTTON": 0.007,
    "RICE": 0.002,
    "WHEAT": 0.008,
    "GEL": 0.000,
}
# 创建问题
prob2 = LpProblem("The Whiskas Problem", LpMinimize)

创建一个名为ingredient_vars的字典,其中包含LP变量,其下限定义为零。字典的引用键是原料名称,数据为Ingr_IngredientName。 (例如:MUTTON:Ingr_MUTTON)

ingredient_vars = LpVariable.dicts("Ingr", Ingredients, 0)

由于costsingredient_vars现在是以成分名称为参考键的字典,因此可以使用列表推导式轻松提取数据

# 目标函数
prob2 += (
    lpSum([costs[i] * ingredient_vars[i] for i in Ingredients]),
    "Total Cost of Ingredients per can",
)
# 五个限制
prob2 += lpSum([ingredient_vars[i] for i in Ingredients]) == 100, "百分比之和"
prob2 += (
    lpSum([proteinPercent[i] * ingredient_vars[i] for i in Ingredients]) >= 8.0,
    "蛋白质需求",
)
prob2 += (
    lpSum([fatPercent[i] * ingredient_vars[i] for i in Ingredients]) >= 6.0,
    "脂肪需求",
)
prob2 += (
    lpSum([fibrePercent[i] * ingredient_vars[i] for i in Ingredients]) <= 2.0,
    "纤维需求",
)
prob2 += (
    lpSum([saltPercent[i] * ingredient_vars[i] for i in Ingredients]) <= 0.4,
    "盐分需求",
)
# 将问题数据写入.lp文件中
prob2.writeLP('WhiskasModel2.lp')
[Ingr_BEEF, Ingr_CHICKEN, Ingr_GEL, Ingr_MUTTON, Ingr_RICE, Ingr_WHEAT]
prob2.solve(CPLEX())
1
print("求解状态:", LpStatus[prob2.status])
求解状态: Optimal
for v in prob2.variables():
    print(v.name, "=", v.varValue)
Ingr_BEEF = 60.0
Ingr_CHICKEN = 0.0
Ingr_GEL = 40.0
Ingr_MUTTON = 0.0
Ingr_RICE = 0.0
Ingr_WHEAT = 0.0
print("每罐猫粮的原材料成本为:", value(prob2.objective))
每罐猫粮的原材料成本为: 0.52

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/853460.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【ROS】message_filters时间同步

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 这篇文章主要介绍message_filters时间同步。 学其所用&#xff0c;用其所学。——梁启超 欢迎来到我的博客&#xff0c;一起学习&#xff0c;共同进步。 喜欢的朋友可以关注一下&#xff0c;下次更新不迷…

接口mock常用工具

在进行测试时&#xff0c;我们经常需要模拟接口数据&#xff0c;尤其是在前后端分离项目的开发中&#xff0c;在后端未完成开发时&#xff0c;前端拿不到后端的数据&#xff0c;就需要对后端返回的数据进行模拟。 如下一些工具&#xff0c;可以完成接口的mock。 Yapi 首先添…

算法通关村——轻松搞定两树相等问题

题目 给你两棵二叉树的根节点p和q&#xff0c;编写一个函数来检验这两棵树是否相同。如果两个树在结构上相同&#xff0c;并且节点具有相同的值&#xff0c;则认为他们是相同的。 示例 输入&#xff1a;p[1,2,3] q[1,2,3] 输出&#xff1a;true 如下图所示&#xff1a; 输入&am…

制造执行系统(MES):优化生产管理的关键

制造业是现代经济的重要组成部分&#xff0c;随着技术的发展和市场需求的变化&#xff0c;制造企业面临着越来越大的挑战。为了在竞争激烈的市场中保持竞争力&#xff0c;企业需要实现生产过程的高效管理和优化。这就引入了制造执行系统&#xff08;MES&#xff09;&#xff0c…

【Spring Boot】了解Spring Boot 的日志文件

目录 一、日志的作用 二、日志文件的简单使用 1、Spring Boot中的默认日志 2、自定义日志打印 三、日志级别 1、日志级别分类 2、日志级别的设置 3、日志持久化 四、基于LomBok的日志输出 1、安装Lombok插件 2、使用Lombok添加日志 3、使用Lombok添加getter和setter…

第48节:cesium 面交集计算(含源码+视频)

结果示例: 完整源码: <template><div class="viewer"><vc-viewer @ready="ready" :logo="false"><vc-navigation

13-把矩阵看作是对系统的描述

探索矩阵乘法&#xff1a;更深刻的理解与应用视角 &#x1f9e9;&#x1f50d; 引言 &#x1f4d6; 在我们进一步探讨矩阵乘法之前&#xff0c;让我们从不同的角度来理解什么是矩阵&#xff0c;以及如何将矩阵视为一个系统。我们之前已经介绍了矩阵的基本概念和运算&#xff…

那些没人教你的Jmeter 循环断言,百度不到的,收藏一下吧

前言 对于使用jmeter工具完成接口测试的测试工程师而言。在工作中&#xff0c;或者在面试中&#xff0c;都会遇到一个问题。 CSV文档做了一大笔测试数据后&#xff0c;怎么去校验这个结果呢&#xff1f; 现在大部分测试工程师可能都是通过人工的方法去查看结果&#xff0c;十几…

【3D卡片切换】基于jquery实现3D堆叠卡片切换效果(附完整源码)

文章目录 写在前面涉及知识点实现效果1、搭建页面1.1 创建ul li节点1.2 丰富元素Html代码所示CSS代码所示 2、JS实现堆叠切换3、源码分享3.1 百度网盘3.2 123云盘3.3 邮箱留言 总结 写在前面 其实3D卡片堆叠切换效果&#xff0c;从我入前端坑以来就一直喜欢的一种轮播效果&…

护网行动 | AD360 在网络安全中的重要作用

随着数字化时代的来临&#xff0c;网络已经成为了人们生活和工作中不可或缺的一部分。然而&#xff0c;随之而来的是网络安全问题日益突出。为了应对这些安全威胁&#xff0c;护网行动应运而生&#xff0c;其中AD360在保障网络安全方面扮演着至关重要的角色。 AD360是一个集成的…

封装上传组件(axios,进度条onUploadProgress,取消请求)

目录 定时模拟进度条 方法 A.axios B.xhr 取消请求​​​​​​​cancelToken A.axios.canceltoken B.source对象创建canceltoken 完整代码 A.自定义上传组件 B.二次封装组件 情况 增加cancelToken不生效&#xff0c;刷新页面 进度条太快->设置浏览器网速 定时…

发布属于自己的 npm 包

1 创建文件夹&#xff0c;并创建 index.js 在文件中声明函数&#xff0c;使用module.exports 导出 2 npm 初始化工具包&#xff0c;package.json 填写包的信息&#xff08;包的名字是唯一的&#xff09; npm init 可在这里写包的名字&#xff0c;或者一路按回车&#xff0c;后…

JedisDataException DENIED Redis is running in protected mode...异常的解决办法

一. 异常现象 壹哥最近在带学生做项目的过程中&#xff0c;有学生在使用Redis的时候&#xff0c;产生了如下这样的异常信息&#xff1a; com.yyg.demo.Demo01Exception in thread "main" redis.clients.jedis.exceptions.JedisDataException: DENIED Redis is runni…

企业邮箱安全对比:哪家公司的产品更可靠?

邮箱仍然是企业沟通的关键组成部分&#xff0c;但往往容易受到安全威胁。为了保护敏感信息&#xff0c;企业需要采取措施使企业邮箱更加安全。这可以通过投资先进的安全解决方案&#xff0c;创建限制或控制访问的策略&#xff0c;并定期对员工进行最佳实践培训来实现。 1、投资…

Java实战:高效提取PDF文件指定坐标的文本内容

前言 临时接到一个紧急需要处理的事项。业务侧一个同事有几千个PDF文件需要整理&#xff1a;需要从文件中的指定位置获取对应的编号和地址。 要的急&#xff0c;工作量大。所以就问到技术部有没有好的解决方案。 问技术的话就只能写个demo跑下了。 解决办法 1. 研究下PDF文档…

B站又添黑马UP主,首发创下1800万播放

众所周知&#xff0c;ACG类是B站最受欢迎的内容&#xff0c;毕竟B站由二次元内容为起点发展至今&#xff0c;吸引了众多年轻一代的用户群体。 而B站又是一个“来自用户”的平台&#xff0c;由用户转变成UP主自发投稿作品&#xff0c;构建出现在这个存在着大大小小几十个分区的…

固定资产管理工作总结

固定资产管理是现代企业管理工作的重点。在过去的一段时间里&#xff0c;企业专注于固定资产管理&#xff0c;以达到节约企业资源的效果。 企业要坚持以标准化管理为载体&#xff0c;制定完善的固定资产管理制度&#xff0c;全面规范固定资产进出口、汇总、储存、维护、损坏等…

利用 3D 地理空间数据实现Cesium的沉浸式环境

推荐&#xff1a;使用 NSDT场景编辑器 助你快速搭建可编辑的3D应用场景 为了将大量异构 3D 地理空间数据处理和分散到各行各业的地理空间应用程序和运行时引擎&#xff0c;Cesium 创建了 3D Tiles&#xff0c;这是一种用于高效流式传输和渲染大量异构数据集的开放标准。3D Tile…

《Python入门到精通》函数详解

「作者主页」&#xff1a;士别三日wyx 「作者简介」&#xff1a;CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」&#xff1a;小白零基础《Python入门到精通》 函数 1、函数的调用2、函数的参数2.1、变量的就近原则2.2、传递参数2.3、形参和实…

恶意扩展可滥用 VS Code 漏洞窃取认证令牌

微软的 Visual Studio Code (VS Code) 代码编辑器存在一个漏洞&#xff0c;允许恶意扩展程序检索 Windows、Linux 和 macOS 中存储的身份验证令牌。 这些令牌用于集成各种第三方服务和 API&#xff0c;如 Git、GitHub 和其他编码平台&#xff0c;因此窃取这些令牌可能会对数据…