浅谈Python数学建模之线性规划

目录
  • 一、求解方法、算法和编程方案
    • 1.1、线性规划问题的求解方法
    • 1.2、线性规划的最快算法
    • 1.3、选择适合自己的编程方案
  • 二、PuLP库求解线性规划问题
    • 2.1、线性规划问题的描述
    • 2.2、PuLP 求解线性规划问题的步骤
    • 2.3、Python例程:线性规划问题
  • 三、小结

一、求解方法、算法和编程方案

线性规划 (Linear Programming,LP) 是很多数模培训讲的第一个算法,算法很简单,思想很深刻。

线性规划问题是中学数学的内容,鸡兔同笼就是一个线性规划问题。数学规划的题目在高考中也经常出现,有直接给出线性约束条件求线性目标函数极值,有间接给出约束条件求线性目标函数极值,还有已知约束条件求非线性目标函数极值问题。

因此,线性规划在数学建模各类问题和算法中确实是比较简单的问题。下面我们通过这个比较简单、也比较熟悉的问题,分析一下数学模型问题的方法、算法和学习方案。探讨这些容易混淆的概念,也便于大家理解本系列教程的初衷和特色。

1.1、线性规划问题的求解方法

解决线性规划问题有很多数学方法,例如:

  • 图解法, 用几何作图的方法并求出其最优解,中学就讲过这种方法,在经济学研究中十分常用;
  • 矩阵法, 引进松弛变量将线性规划问题转换成增广矩阵形式后逐次求解, 是单纯性法之前的典型方法;
  • 单纯性法, 利用多面体在可行域内逐步构造新的顶点来不断逼近最优解,是线性规划研究的里程碑,至今仍然是最重要的方法之一;
  • 内点法,通过选取可行域内部点沿下降方向不断迭代来达到最优解,是目前理论上最好的线性规划问题求解方法;
  • 启发式方法,依靠经验准则不断迭代改进来搜索最优解 ,如贪心法、模拟退火、遗传算法、神经网络。

虽然不同的求解方法都是面对线性规划问题,也就必然会殊途同归,但它们在思想上就存在着本质区别,在求解方法和步骤上也就完全不同。

不夸张地说,对于很多小白,学没学过单纯性法,对于学习启发式方法可能完全没有区别。

这意味着什么呢?这就是说,对于非数学专业的同学,对于学习数学建模的同学,针对每一类问题,完全没必要学习各种解决方法。即便是数学专业的同学,也不可能在数模学习期间把各种方法都学会。

对于小白,本文推荐选择较为通用、相对简单(思路简单、程序简单)的方法来进行学习,没必要贪多求新。

1.2、线性规划的最快算法

算法,跟方法有什么不同呢?

算法的定义是“解题方案的准确而完整的描述”,是一系列解决问题的清晰指令,算法代表着用系统的方法描述解决问题的策略机制。

我对“方法”的理解是思想方法,是求解问题总体框架,而“算法”是具体和明确的实现步骤,在计算机编程中相当于详细的流程图。

在每一种方法的基本思想和方案提出后,往往都会有很多变形、改进和发展的算法。极少的改进算法具有实质贡献而成为主流的经典算法,即便如此往往也只是性能、效率上的提升,对于求解数模竞赛中的问题基本没有影响。

而绝大多数改进算法只是针对某些特殊情况、特殊问题(自称)有效,常用于大量的灌水论文。对于数学建模来说,学习基本算法或者目前的经典算法就足够了,不需要听信改进算法中自称的优点,那都是莆田系的广告。

有一种例外情况,就是一些算法是有适用范围和限制条件的。举个例子,内点法的基本算法不能处理等式约束,最短路径问题中 Dijkstar算法不能处理负权边。这种情况下如果选错算法,问题是无法求解的。所以对我们来说,搞清楚算法的适用范围,比理解算法本身更重要。

回到本节的标题,对于线性规划问题,什么算法是最快的呢?答案是:猜。不是让你猜,而是说求解线性规划问题,猜起来比较快。不是开玩笑,我是认真的。

佐治亚理工学院彭泱教授在 2021年计算机理论顶会 SODA2021 获得最佳论文(Best paper award at ACM-SIAM symposium on discrete algorithms 2021),正是研究线性规划问题的求解——“Solving sparse linear systems faster than matrix multiplication”,所用的全新思路是:猜,反复猜,迭代猜。

当然,猜起来比较快只是在某些特殊条件下才有效的,至于在什么条件下猜,怎么猜,这不是我们所要关心,所能理解的问题了。只是以此说明,简单的问题也有复杂的情况,每个问题都有很多求解的思路、方法和算法。

1.3、选择适合自己的编程方案

编程方案是我杜撰的术语。我所要表达意思是,在选择了求解方法和算法以后,是自己按照算法步骤一步步编程实现,或者找到例程调试使用,还是调用第三方工具包/库函数来完成呢?

首先,对于学习数学建模、参加数模竞赛,不建议自己按照算法步骤去编程。我们在《01.新手必读》中讨论过这个问题,对于数学小白兼计算机小白,这样做既不可行也没必要;即使你愿意挑战自我去试试,那其实已经是走在学习另一门计算机或算法课程的路上了。

其次,要不要找到例程自己调试、使用?很多数模培训就是这么说,这么做的,而且把这些收集的例程当作核心机密吸引同学。我不反对这样做,这种学习方法对于理解算法、提高编程能力很有帮助;但是并不推荐这样做,原因是:

(1)我认为学习数学建模、参加数模竞赛,重点应该放在识别问题、分析问题、解决问题,能使用算法和编程就足够了;

(2)第三方库与例程没有本质区别,第三方库就是经典的、规范的、标准化的例程,既然选择例程为什么不选择优秀的例程——第三方库呢?

(3)大部分例程都存在很多问题,即使调试通过仍然有很多坑,而且新手难以识别。

所以我是明确推荐优选直接使用第三方库来解决问题,这也是 Python 语言“不要重复造轮子”的思想。

进一步地,很多工具包/库函数都能实现常用的算法,应该如何选择呢?

如果你对某个工具包已经很熟悉,又能实现所要的算法,这当然是理想的选择。如果你是小白,就跟着我走吧。

本系列选择第三方工具包的原则是:

(1)优选常用的工具包;

(2)优选通用功能的工具包和函数(例如,最好既能实现线性规划,又能实现整数规划、非线性规划);

(3)优选安装简单、使用简单、配置灵活的工具包;

(4)优选兼模型检验、图形绘制的工具包。

二、PuLP库求解线性规划问题

2.1、线性规划问题的描述

线性规划是研究线性等式或不等式约束条件下求解线性目标函数的极值问题,常用于解决资源分配、生产调度和混合问题。

一般线性规划问题的标准形式为:

满足所有约束条件的解,称为线性规划问题的可行解;所有可行解构成的集合,称为可行域。

使目标函数达到最小值的解,称为最优解。

线性规划问题的建模和求解,通常按照以下步骤进行:

  • 问题定义,确定决策变量、目标函数和约束条件;
  • 模型构建,由问题描述建立数学方程,并转化为标准形式的数学模型;
  • 模型求解,用标准模型的优化算法对模型求解,得到优化结果。

很多 Python 的第三方包,都提供求解线性规划问题的算法,有的工具包还提供整数规划、非线性规划的算法。例如:

  • Scipy 库提供了解简单线性或非线性规划问题,但是不能求解如背包问题的0-1规划问题,或整数规划问题,混合整数规划问题。
  • PuLP 可以求解线性规划、整数规划、0-1规划、混合整数规划问题,提供多种针对不同类型问题的求解器。
  • Cvxpy 是一种凸优化工具包,可以求解线性规划、整数规划、0-1规划、混合整数规划、二次规划和几何规划问题。

此外,SKlearn、DOcplex、Pymprog 等很多第三方工具包也都能求解线性规划问题。

2.2、PuLP 求解线性规划问题的步骤

例题 1:

下面以该题为例讲解 PuLP 求解线性规划问题的步骤:

(0)导入 PuLP库函数

import pulp

(1)定义一个规划问题

MyProbLP = pulp.LpProblem("LPProbDemo1", sense=pulp.LpMaximize)

pulp.LpProblem 是定义问题的构造函数。

"LPProbDemo1"是用户定义的问题名(用于输出信息)。

参数 sense 用来指定求最小值/最大值问题,可选参数值:LpMinimize、LpMaximize 。本例 “sense=pulp.LpMaximize” 表示求目标函数的最大值。

(2)定义决策变量

x1 = pulp.LpVariable('x1', lowBound=0, upBound=7, cat='Continuous')
x2 = pulp.LpVariable('x2', lowBound=0, upBound=7, cat='Continuous')
x3 = pulp.LpVariable('x3', lowBound=0, upBound=7, cat='Continuous') 

pulp.LpVariable 是定义决策变量的函数。
'x1' 是用户定义的变量名。

参数 lowBound、upBound 用来设定决策变量的下界、上界;可以不定义下界/上界,默认的下界/上界是负无穷/正无穷。本例中 x1,x2,x3 的取值区间为 [0,7]。

参数 cat 用来设定变量类型,可选参数值:'Continuous' 表示连续变量(默认值)、' Integer ' 表示离散变量(用于整数规划问题)、' Binary ' 表示0/1变量(用于0/1规划问题)。

(3)添加目标函数

MyProbLP += 2*x1 + 3*x2 - 5*x3  	# 设置目标函数

添加目标函数使用 "问题名 += 目标函数式" 格式。

(4)添加约束条件

MyProbLP += (2*x1 - 5*x2 + x3 >= 10)  # 不等式约束
MyProbLP += (x1 + 3*x2 + x3 <= 12)  # 不等式约束
MyProbLP += (x1 + x2 + x3 == 7)  # 等式约束

添加约束条件使用 "问题名 += 约束条件表达式" 格式。

约束条件可以是等式约束或不等式约束,不等式约束可以是 小于等于 或 大于等于,分别使用关键字">="、"<="和"=="。

(5)求解

MyProbLP.solve()
print("Status:", pulp.LpStatus[MyProbLP.status]) # 输出求解状态
for v in MyProbLP.variables():
    print(v.name, "=", v.varValue)  # 输出每个变量的最优值
print("F(x) = ", pulp.value(MyProbLP.objective))  #输出最优解的目标函数值   

solve() 是求解函数。PuLP默认采用 CBC 求解器来求解优化问题,也可以调用其它的优化器来求解,如:GLPK,COIN CLP/CBC,CPLEX,和GUROBI,但需要另外安装。 

2.3、Python例程:线性规划问题

例程 1:求解线性规划问题

import pulp
MyProbLP = pulp.LpProblem("LPProbDemo1", sense=pulp.LpMaximize)  # 求最大值
x1 = pulp.LpVariable('x1', lowBound=0, upBound=7, cat='Continuous')
x2 = pulp.LpVariable('x2', lowBound=0, upBound=7, cat='Continuous')
x3 = pulp.LpVariable('x3', lowBound=0, upBound=7, cat='Continuous')
MyProbLP += 2*x1 + 3*x2 - 5*x3  	# 设置目标函数
MyProbLP += (2*x1 - 5*x2 + x3 >= 10)  # 不等式约束
MyProbLP += (x1 + 3*x2 + x3 <= 12)  # 不等式约束
MyProbLP += (x1 + x2 + x3 == 7)  # 等式约束
MyProbLP.solve()  # youcans@xupt
print("Status:", pulp.LpStatus[MyProbLP.status]) # 输出求解状态
for v in MyProbLP.variables():  # youcans
    print(v.name, "=", v.varValue)  # 输出每个变量的最优值
print("Max F(x) = ", pulp.value(MyProbLP.objective))  #输出最优解的目标函数值

例程 1 运行结果:

Welcome to the CBC MILP Solver 

Version: 2.9.0 

Build Date: Feb 12 2015 

Status: Optimal

x1 = 6.4285714

x2 = 0.57142857

x3 = 0.0

Max F(x) =  14.57142851

例程01 程序说明:

  • 用 PuLP 库求解线性规划问题,可以选择求最大值或最小值,可以按照问题的数学描述,直接输入目标函数、等式约束和不等式约束,不等式约束可以选择 <= 或 >=,不需要进行转换。这中方式简单直观,非常适合初学者掌握。
  • 对于较大规模线性规划问题, PuLP 库支持用字典类型(dict)建立多个变量,设置目标函数和约束条件。

三、小结

求解线性规划问题的方法非常简单,本文实际上并未讲解具体的算法。

希望通过对求解方法、算法和编程方案的讲解,阐明作者对于数学建模学什么、怎么学的理解,也使读者能了解本系列教程的特点:本教程不打算详细讲解各种算法的具体方法,重点介绍如何使用第三方包实现算法、解决问题。

以上就是浅谈Python数学建模之线性规划的详细内容,更多关于Python 线性规划的资料请关注我们其它相关文章!

(0)

相关推荐

  • Java动态规划之硬币找零问题实现代码

    动态规划的基本思想是将待求解问题分解成若干个子问题,先求解子问题,并将这些子问题的解保存起来,如果以后在求解较大子问题的时候需要用到这些子问题的解,就可以直接取出这些已经计算过的解而免去重复运算.保存子问题的解可以使用填表方式,例如保存在数组中. 用一个实际例子来体现动态规划的算法思想--硬币找零问题. 问题描述: 假设有几种硬币,并且数量无限.请找出能够组成某个数目的找零所使用最少的硬币数.例如几种硬币为[1, 3, 5], 面值2的最少硬币数为2(1, 1), 面值4的最少硬币数为2(1,

  • python 非线性规划方式(scipy.optimize.minimize)

    一.背景: 现在项目上有一个用python 实现非线性规划的需求.非线性规划可以简单分两种,目标函数为凸函数 or 非凸函数. 凸函数的 非线性规划,比如fun=x^2+y^2+x*y,有很多常用的python库来完成,网上也有很多资料,比如CVXPY 非凸函数的 非线性规划(求极值),从处理方法来说,可以尝试以下几种: 1.纯数学方法,求导求极值: 2.使用神经网络,深度学习来处理,可参考反向传播算法中链式求导的过程: 3.寻找一些python库来做,本文介绍scipy.optimize.mi

  • 动态规划之矩阵连乘问题Python实现方法

    本文实例讲述了动态规划之矩阵连乘问题Python实现方法.分享给大家供大家参考,具体如下: 给定n个矩阵{A1,A2,-,An},其中Ai与Ai+1是可乘的,i=1,2 ,-,n-1.如何确定计算矩阵连乘积的计算次序,使得依此次序计算矩阵连乘积需要的数乘次数最少. 例如: A1={30x35} ; A2={35x15} ;A3={15x5} ;A4={5x10} ;A5={10x20} ;A6={20x25} ; 结果为:((A1(A2A3))((A4A5)A6))  最小的乘次为15125.

  • 分析python动态规划的递归、非递归实现

    概要 本文只是简单的介绍动态规划递归.非递归算法实现 案例一 题目一:求数组非相邻最大和 [题目描述] 在一个数组arr中,找出一组不相邻的数字,使得最后的和最大. [示例输入] arr=1 2 4 1 7 8 3 [示例输出] 15 from functools import wraps def memoDeco(func): ''' memoDeco主要是缓存已遍历的节点,减少递归内存开销 ''' cashe={} @wraps(func) def wrapper(*args): if ar

  • Python二次规划和线性规划使用实例

    这篇文章主要介绍了Python二次规划和线性规划使用实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 对于二次规划(quadratic programming)和线性规划(Linear Programming)问题 MATLAB里是有quadprog函数可以直接用来解决二次规划问题的,linprog函数来解决线性规划问题.Python中也有很多库用来解决,对于二次规划有CVXOPT, CVXPY, Gurobi, MOSEK, qpOASES

  • Python基于动态规划算法解决01背包问题实例

    本文实例讲述了Python基于动态规划算法解决01背包问题.分享给大家供大家参考,具体如下: 在01背包问题中,在选择是否要把一个物品加到背包中,必须把该物品加进去的子问题的解与不取该物品的子问题的解进行比较,这种方式形成的问题导致了许多重叠子问题,使用动态规划来解决.n=5是物品的数量,c=10是书包能承受的重量,w=[2,2,6,5,4]是每个物品的重量,v=[6,3,5,4,6]是每个物品的价值,先把递归的定义写出来: 然后自底向上实现,代码如下: def bag(n,c,w,v): re

  • Java动态规划之编辑距离问题示例代码

    动态规划过程是:每次决策依赖于当前状态,又随即引起状态的转移.一个决策序列就是在变化的状态中产生出来的,所以,这种多阶段最优化决策解决问题的过程就称为动态规划. 动态规划实际上是一类题目的总称,并不是指某个固定的算法.动态规划的意义就是通过采用递推(或者分而治之)的策略,通过解决大问题的子问题从而解决整体的做法.动态规划的核心思想是巧妙的将问题拆分成多个子问题,通过计算子问题而得到整体问题的解.而子问题又可以拆分成更多的子问题,从而用类似递推迭代的方法解决要求的问题.问题描述: 对于序列S和T,

  • 浅谈Python数学建模之线性规划

    目录 一.求解方法.算法和编程方案 1.1.线性规划问题的求解方法 1.2.线性规划的最快算法 1.3.选择适合自己的编程方案 二.PuLP库求解线性规划问题 2.1.线性规划问题的描述 2.2.PuLP 求解线性规划问题的步骤 2.3.Python例程:线性规划问题 三.小结 一.求解方法.算法和编程方案 线性规划 (Linear Programming,LP) 是很多数模培训讲的第一个算法,算法很简单,思想很深刻. 线性规划问题是中学数学的内容,鸡兔同笼就是一个线性规划问题.数学规划的题目在

  • 浅谈Python数学建模之固定费用问题

    目录 一.固定费用问题案例解析 1.1.固定费用问题(Fixed cost problem) 1.2.案例问题描述 1.3.建模过程分析 1.4.PuLP 求解固定费用问题的编程 1.5.Python 例程:固定费用问题 1.6.Python 例程运行结果 二.PuLP 求解规划问题的快捷方法 2.1.PuLP 求解固定费用问题的编程 2.2.Python 例程:PuLP 快捷方法 2.3.Python 例程运行结果 一.固定费用问题案例解析 1.1.固定费用问题(Fixed cost prob

  • 浅谈Python数学建模之整数规划

    目录 一.从线性规划到整数规划 1.1.为什么会有整数规划? 1.2.四舍五入就能得到整数解吗? 二.整数规划的求解方法 2.1.分支定界法(Branch and bound) 2.2.割平面法(Cutting plane) 2.3.整数规划的编程方案 三.PuLP 求解整数规划问题 3.1.案例问题描述 3.2.建模过程分析 3.2.1.问题定义 3.2.2.模型构建 3.2.3.模型求解 3.3.Python 例程 3.4.Python 例程运行结果 一.从线性规划到整数规划 1.1.为什么

  • 浅谈Python数学建模之数据导入

    目录 一.数据导入是所有数模编程的第一步 二.在程序中直接向变量赋值 2.1.为什么直接赋值? 2.2.直接赋值的问题与注意事项 三.Pandas 导入数据 3.1.Pandas 读取 Excel 文件 3.2.Pandas 读取 csv 文件 3.3.Pandas 读取文本文件 3.4.Pandas 读取其它文件格式 四.数据导入例程 一.数据导入是所有数模编程的第一步 编程求解一个数模问题,问题总会涉及一些数据. 有些数据是在题目的文字描述中给出的,有些数据是通过题目的附件文件下载或指定网址

  • Python数学建模PuLP库线性规划实际案例编程详解

    目录 1.问题描述 2.用PuLP 库求解线性规划 2.1 问题 1 (1)数学建模 (2)Python 编程 (3)运行结果 2.2 问题 2 (1)数学建模 (2)Python 编程 (3)运行结果 2.3 问题 3 (1)数学建模 (2)Python 编程 (3)运行结果 2.4 问题 4 (1)数学建模 (2)Python 编程 (3)运行结果 2.5 问题 5:整数规划问题 (1)数学建模 (2)Python 编程 (3)运行结果 1.问题描述 某厂生产甲乙两种饮料,每百箱甲饮料需用原

  • Python数学建模PuLP库线性规划进阶基于字典详解

    目录 1.基于字典的创建规划问题 2.线性规划问题案例 3.建立模型 (1)决策变量 (2)目标函数 (3)约束条件 (4)变量取值范围 4.PuLP 程序1:使用 LpVariable 逐一定义变量 5.PuLP 程序2:使用 dict 定义决策变量和约束条件 6.Python程序和运行结果 1.基于字典的创建规划问题 上篇中介绍了使用 LpVariable 对逐一定义每个决策变量,设定名称.类型和上下界,类似地对约束条件也需要逐一设置模型参数.在大规模的规划问题中,这样逐个定义变量和设置模型

  • Python数学建模PuLP库线性规划入门示例详解

    目录 1.什么是线性规划 2.PuLP 库求解线性规划 -(0)导入 PuLP库函数 -(1)定义一个规划问题 -(2)定义决策变量 -(3)添加目标函数 -(4)添加约束条件 -(5)求解 3.Python程序和运行结果 1.什么是线性规划 线性规划(Linear programming),在线性等式或不等式约束条件下求解线性目标函数的极值问题,常用于解决资源分配.生产调度和混合问题.例如: max fx = 2*x1 + 3*x2 - 5*x3 s.t. x1 + 3*x2 + x3 <=

  • 浅谈Python数据类型之间的转换

    Python数据类型之间的转换 函数 描述 int(x [,base]) 将x转换为一个整数 long(x [,base] ) 将x转换为一个长整数 float(x) 将x转换到一个浮点数 complex(real [,imag]) 创建一个复数 str(x) 将对象 x 转换为字符串 repr(x) 将对象 x 转换为表达式字符串 eval(str) 用来计算在字符串中的有效Python表达式,并返回一个对象 tuple(s) 将序列 s 转换为一个元组 list(s) 将序列 s 转换为一个

  • 浅谈python中的数字类型与处理工具

    python中的数字类型工具 python中为更高级的工作提供很多高级数字编程支持和对象,其中数字类型的完整工具包括: 1.整数与浮点型, 2.复数, 3.固定精度十进制数, 4.有理分数, 5.集合, 6.布尔类型 7.无穷的整数精度 8.各种数字内置函数及模块. 基本数字类型 python中提供了两种基本类型:整数(正整数金额负整数)和浮点数(注:带有小数部分的数字),其中python中我们可以使用多种进制的整数.并且整数可以用有无穷精度. 整数的表现形式以十进制数字字符串写法出现,浮点数带

  • 浅谈python数据类型及其操作

    一. Number 数字 1.内置函数:需要导入math 2.随机数函数:需要导入random 模块 3.三角函数:需要导入math模块 4.数学常量:需要导入math模块 #1.数据函数的使用 #========================== #内置函数 print(abs(-10)) #10绝对值 print(round(4.56789,2)) #4.57 使用四舍五入的方式保留小数点后两位 a = [10,30,20,80,50] print(max(a)) #80 最大值 prin

随机推荐