PuLP库-多数线性规划问题

2024-01-27 02:04

本文主要是介绍PuLP库-多数线性规划问题,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

投标价格重预算

背景

甲方需要采购一批物资,采购数量为甲方给定的预计采购数量,并限制了采购总价。例甲方采购预算清单如下,采购总预算为不超过 3175 元

采购内容采购数量投标单价投标报价合计
电脑10
空调20
洗衣机8
桌子7
打印机35
合计

注:乙方根据以上预算清单填报单价,最终数量按实结算,单价不变

我方竞标时在甲方预算清单内填报单价,假设我方报价如下:

采购内容采购数量投标单价投标报价合计
电脑1015150
空调2020400
洗衣机835280
桌子775525
打印机35521820
合计3175

最终项目实施完毕后,结算是根据实际实施数量*投标单价进行结算,根据经验我们能判断最终那些数量会增加实施,那些数量会减少实施,假设实际实施数量如下(电脑增加了 3 台,空调减少了 2 台…)

采购内容采购数量投标单价投标报价合计
电脑13
空调18
洗衣机7
桌子7
打印机38
合计3175

由此产生了需求,求出在总报价不变的情况下,针对最终实施数量会减少的部分,尽可能的报低单价,针对最终实施数量会增加的部分报高单价,对于各个商品的单价变化幅度有一个同一的范围,以达到结算的时候利益最大化。

最终需求:在已知最终数量的情况下,报价单价策略应该填多少,利益才能最大化,也就是我们需要求的那个最大值。

img

问题分析

我们对上面图片中的内容进行划分,从左到右分别为A、B、C、D、E、F、G列,D列各行的值为B*C,在最后还有对于所有采购商品的总价汇总。A、B、C、E列的值已经给出,现在需要求出D、F、G列的内容,此处略过D列数据的求解,着重分析F列的求值。
假设X列从上至下的值为一个数组 $(x_1, x_2, …, x_n) ,那么 F 列的值为 ,那么F列的值为 ,那么F列的值为(f_1, f_2, …, f_n)$,B列的值为(b_1, b_2, …, b_n),C列的值为(c_1, c_2, …, c_n),按照题目中所给的条件,我们可以得到以下两个约束条件:

  1. 一个1 * n的矩阵B与一个n * 1的矩阵C点乘后的结果 == 一个1 * n的矩阵B与一个n * 1的矩阵F点乘的结果
  2. f i ∗ ( 1 − m a x D e c r e a s e ) < = f i < = f i ∗ ( 1 + m a x I n c r e a s e ) f_i * (1 - maxDecrease) <= f_i <= f_i * (1 + maxIncrease) fi(1maxDecrease)<=fi<=fi(1+maxIncrease)
  3. s u m = ∑ i = 1 n f i sum = \sum_{i=1}^n f_i sum=i=1nfi

仔细一分析过后,我们可以发现我们仔细分析了一下,我们可以发现,这是一个线性规划问题,没错,就是高中时期常常出现在填空题里的那个属于送分题的线性规划问题,只不过从高中时期的不超过4个限制条件变成了n个而已,没有什么难的。此时我们开始思考一个问题,那就是如何构造一个多数线性规划模型,并能够针对限制条件数量未知的情况来进行模型的快速调用,并实现限制条件和结果的输入以及得出。

所幸,Python中有这么一个库,能够实现我们当前面临问题的完美解决。

相关依赖库

主要介绍实现过程中的几个重要库,其余库的具体安装要求请参照项目下的requirements.txt文件,以下是关于几个重要库的介绍。

PuLP

如果你在百度里搜索Python PuLP,你会发现与之相关联的词条除了一个同名的乐队之外,还有优化问题以及混合整数规划(MILP)这两个词条。如果你在google里面搜索同样的词条,至少前一页都是Pulp库以及线性规划相关的内容。不同的搜索引擎都能找到的共同点就是,pulp在线性规划问题方面的使用。

在pulp库的文档中你可以看到有这么一个关于猫粮中原料配比的问题,如果你看不懂英文,可以看下面的这个文档,这是某个知乎上的前人写的说明,基本上已经将原本文档中的内容进行了翻译,大家可以着重看代码部分:

# 导入 PulP
from pulp import *# 建立线性规划问题,指定名称:CatFood, 问题的目标:求解最小值 LpMinimize
prob = pulp.LpProblem(name='CatFood', sense=LpMinimize)# 定义变量: 鸡肉占比,设置下限值为 0 , 不能是负数
x1 = LpVariable("鸡肉占比", lowBound=0)# 定义变量: 牛肉占比,设置下限值为 0 , 不能是负数
x2= LpVariable("牛肉占比", lowBound=0)# 将目标函数用 += 方式附加到 prob 变量
prob += 0.013*x1 + 0.008*x2, "最小成本"# 将约束条件用 += 方式附加到 prob 变量,注意区别是约束条件有判断操作符
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, "盐含量"# 将问题输出为 lp 文件
prob.writeLP('catfood.lp')

此处并没有将问题进行解决,只是通过代码的描述,将问题的内容实现了自生成,你会得到一个catfood.lp文件,里面的内容长这样:

# 查看输出的 lp 文件
! cat catfood.lp
\* CatFood *\
Minimize
最小成本: 0.008 牛肉占比 + 0.013 鸡肉占比
Subject To
占比总和: 牛肉占比 + 鸡肉占比 = 100
盐含量: 0.005 牛肉占比 + 0.002 鸡肉占比 <= 0.4
纤维含量: 0.005 牛肉占比 + 0.001 鸡肉占比 <= 2
脂肪含量: 0.1 牛肉占比 + 0.08 鸡肉占比 >= 6
蛋白质含量: 0.2 牛肉占比 + 0.1 鸡肉占比 >= 8
End

是的,他没什么用处,只是给我们看看的。but,这只是这个知乎的作者没有认真思考照单全抄的缘故,因为此时的我们完全可以将上面的问题通过当前库进行解决(一个库如果只能将问题进行描述但不能实现解决,这就相当于上厕所不仅没有纸而且没有水),只需再加几行代码:

# 用求解器解决问题
prob.solve()# 查看求解器的状态
# 返回的状态是 : Not Solved, Infeasible, Unbounded, Undefined, Optimal
# Optimal 就是有最优解
print("Status:", LpStatus[prob.status])
# 查看变量的值
for v in prob.variables():print(v.name, "=", v.varValue, '%')print( "每100克猫粮的最小成本 = ", value(prob.objective))

添加以上代码后可以实现在控制台输出最终的结果。

此时,我们又面临一个问题,如何添加多个参数,可能很多很多个参数,是的,这个问题有点让人头秃,but,在这里,我不得不说,写了这个库的人真是个天才,因为他提供了一个addVariable()方法,使得我们可以通过遍历已有的数据实现对问题限制条件的批量化添加,比如这样:

    for i in range(10):v = pulp.LpVariable(key_list[i], lowBound=original_price[i], upBound=original_price[i] * (1 + max_increase),cat='Continuous')MyProblem.addVariable(v)

其中key_list中元素为str类型,original_price中元素为数字类型,max_increase是数字。

最终,我们通过构建这个规划问题,实现了投标单价修改值的求解。具体代码由于当前代码属于商用的开发阶段,不方便直接展示,具体实现请查看version包下的budget_bid_price_version_01.py文件,所有的代码已上传到github仓库。

这篇关于PuLP库-多数线性规划问题的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/648737

相关文章

大数据小内存排序问题如何巧妙解决

《大数据小内存排序问题如何巧妙解决》文章介绍了大数据小内存排序的三种方法:数据库排序、分治法和位图法,数据库排序简单但速度慢,对设备要求高;分治法高效但实现复杂;位图法可读性差,但存储空间受限... 目录三种方法:方法概要数据库排序(http://www.chinasem.cn对数据库设备要求较高)分治法(常

Vue项目中Element UI组件未注册的问题原因及解决方法

《Vue项目中ElementUI组件未注册的问题原因及解决方法》在Vue项目中使用ElementUI组件库时,开发者可能会遇到一些常见问题,例如组件未正确注册导致的警告或错误,本文将详细探讨这些问题... 目录引言一、问题背景1.1 错误信息分析1.2 问题原因二、解决方法2.1 全局引入 Element

关于@MapperScan和@ComponentScan的使用问题

《关于@MapperScan和@ComponentScan的使用问题》文章介绍了在使用`@MapperScan`和`@ComponentScan`时可能会遇到的包扫描冲突问题,并提供了解决方法,同时,... 目录@MapperScan和@ComponentScan的使用问题报错如下原因解决办法课外拓展总结@

MybatisGenerator文件生成不出对应文件的问题

《MybatisGenerator文件生成不出对应文件的问题》本文介绍了使用MybatisGenerator生成文件时遇到的问题及解决方法,主要步骤包括检查目标表是否存在、是否能连接到数据库、配置生成... 目录MyBATisGenerator 文件生成不出对应文件先在项目结构里引入“targetProje

C#使用HttpClient进行Post请求出现超时问题的解决及优化

《C#使用HttpClient进行Post请求出现超时问题的解决及优化》最近我的控制台程序发现有时候总是出现请求超时等问题,通常好几分钟最多只有3-4个请求,在使用apipost发现并发10个5分钟也... 目录优化结论单例HttpClient连接池耗尽和并发并发异步最终优化后优化结论我直接上优化结论吧,

Java内存泄漏问题的排查、优化与最佳实践

《Java内存泄漏问题的排查、优化与最佳实践》在Java开发中,内存泄漏是一个常见且令人头疼的问题,内存泄漏指的是程序在运行过程中,已经不再使用的对象没有被及时释放,从而导致内存占用不断增加,最终... 目录引言1. 什么是内存泄漏?常见的内存泄漏情况2. 如何排查 Java 中的内存泄漏?2.1 使用 J

numpy求解线性代数相关问题

《numpy求解线性代数相关问题》本文主要介绍了numpy求解线性代数相关问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 在numpy中有numpy.array类型和numpy.mat类型,前者是数组类型,后者是矩阵类型。数组

解决systemctl reload nginx重启Nginx服务报错:Job for nginx.service invalid问题

《解决systemctlreloadnginx重启Nginx服务报错:Jobfornginx.serviceinvalid问题》文章描述了通过`systemctlstatusnginx.se... 目录systemctl reload nginx重启Nginx服务报错:Job for nginx.javas

Redis缓存问题与缓存更新机制详解

《Redis缓存问题与缓存更新机制详解》本文主要介绍了缓存问题及其解决方案,包括缓存穿透、缓存击穿、缓存雪崩等问题的成因以及相应的预防和解决方法,同时,还详细探讨了缓存更新机制,包括不同情况下的缓存更... 目录一、缓存问题1.1 缓存穿透1.1.1 问题来源1.1.2 解决方案1.2 缓存击穿1.2.1

vue解决子组件样式覆盖问题scoped deep

《vue解决子组件样式覆盖问题scopeddeep》文章主要介绍了在Vue项目中处理全局样式和局部样式的方法,包括使用scoped属性和深度选择器(/deep/)来覆盖子组件的样式,作者建议所有组件... 目录前言scoped分析deep分析使用总结所有组件必须加scoped父组件覆盖子组件使用deep前言