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

相关文章

SpringBoot首笔交易慢问题排查与优化方案

《SpringBoot首笔交易慢问题排查与优化方案》在我们的微服务项目中,遇到这样的问题:应用启动后,第一笔交易响应耗时高达4、5秒,而后续请求均能在毫秒级完成,这不仅触发监控告警,也极大影响了用户体... 目录问题背景排查步骤1. 日志分析2. 性能工具定位优化方案:提前预热各种资源1. Flowable

springboot循环依赖问题案例代码及解决办法

《springboot循环依赖问题案例代码及解决办法》在SpringBoot中,如果两个或多个Bean之间存在循环依赖(即BeanA依赖BeanB,而BeanB又依赖BeanA),会导致Spring的... 目录1. 什么是循环依赖?2. 循环依赖的场景案例3. 解决循环依赖的常见方法方法 1:使用 @La

SpringBoot启动报错的11个高频问题排查与解决终极指南

《SpringBoot启动报错的11个高频问题排查与解决终极指南》这篇文章主要为大家详细介绍了SpringBoot启动报错的11个高频问题的排查与解决,文中的示例代码讲解详细,感兴趣的小伙伴可以了解一... 目录1. 依赖冲突:NoSuchMethodError 的终极解法2. Bean注入失败:No qu

MySQL新增字段后Java实体未更新的潜在问题与解决方案

《MySQL新增字段后Java实体未更新的潜在问题与解决方案》在Java+MySQL的开发中,我们通常使用ORM框架来映射数据库表与Java对象,但有时候,数据库表结构变更(如新增字段)后,开发人员可... 目录引言1. 问题背景:数据库与 Java 实体不同步1.1 常见场景1.2 示例代码2. 不同操作

如何解决mysql出现Incorrect string value for column ‘表项‘ at row 1错误问题

《如何解决mysql出现Incorrectstringvalueforcolumn‘表项‘atrow1错误问题》:本文主要介绍如何解决mysql出现Incorrectstringv... 目录mysql出现Incorrect string value for column ‘表项‘ at row 1错误报错

如何解决Spring MVC中响应乱码问题

《如何解决SpringMVC中响应乱码问题》:本文主要介绍如何解决SpringMVC中响应乱码问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Spring MVC最新响应中乱码解决方式以前的解决办法这是比较通用的一种方法总结Spring MVC最新响应中乱码解

pip无法安装osgeo失败的问题解决

《pip无法安装osgeo失败的问题解决》本文主要介绍了pip无法安装osgeo失败的问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 进入官方提供的扩展包下载网站寻找版本适配的whl文件注意:要选择cp(python版本)和你py

解决Java中基于GeoTools的Shapefile读取乱码的问题

《解决Java中基于GeoTools的Shapefile读取乱码的问题》本文主要讨论了在使用Java编程语言进行地理信息数据解析时遇到的Shapefile属性信息乱码问题,以及根据不同的编码设置进行属... 目录前言1、Shapefile属性字段编码的情况:一、Shp文件常见的字符集编码1、System编码

Spring MVC使用视图解析的问题解读

《SpringMVC使用视图解析的问题解读》:本文主要介绍SpringMVC使用视图解析的问题解读,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Spring MVC使用视图解析1. 会使用视图解析的情况2. 不会使用视图解析的情况总结Spring MVC使用视图

Redis解决缓存击穿问题的两种方法

《Redis解决缓存击穿问题的两种方法》缓存击穿问题也叫热点Key问题,就是⼀个被高并发访问并且缓存重建业务较复杂的key突然失效了,无数的请求访问会在瞬间给数据库带来巨大的冲击,本文给大家介绍了Re... 目录引言解决办法互斥锁(强一致,性能差)逻辑过期(高可用,性能优)设计逻辑过期时间引言缓存击穿:给