Python数学建模:线性规划求解方法与PuLP库实战指南

唐可
唐可
发布时间:2026-10-14 | 3人浏览过
原创

本文深入解析线性规划在数学建模中的应用,对比图解法、单纯形法等传统算法与启发式方法的差异。重点介绍Python中PuLP库的标准用法,涵盖变量定义、目标函数构建及约束条件添加,通过完整代码示例演示如何高效求解线性规划问题,适合初学者快速掌握建模编程技巧。

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

线性规划(Linear Programming,LP)通常是数学建模培训中引入的第一个核心算法。虽然其基础概念看似简单,但背后蕴含的数学思想却十分深刻。

线性规划问题早在中学数学阶段便已出现,例如经典的“鸡兔同笼”问题本质上就是一个线性规划案例。在高考数学中,这类题目频繁出现,形式包括直接给出线性约束条件求目标函数极值、间接给出约束条件求极值,以及已知约束条件求解非线性目标函数的极值问题。

因此,在各类数学建模问题和算法体系中,线性规划属于相对基础且简单的范畴。接下来,我们将通过这一熟悉且相对简单的问题,深入剖析数学建模问题的处理方法、算法逻辑及学习路径,探讨那些容易混淆的概念,从而帮助读者更好地理解本系列教程的初衷与特色。

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

解决线性规划问题存在多种数学途径,主要包括以下几种:

  • 图解法:这是一种通过几何作图寻找最优解的方法,在中学阶段已有涉及,在经济学研究领域应用广泛;
  • 矩阵法:通过引入松弛变量将线性规划问题转化为增广矩阵形式,进而进行逐步求解,这是单纯形法出现前的典型处理方式;
  • 单纯形法:该方法利用多面体在可行域内逐步构造新顶点以逼近最优解,被视为线性规划研究的里程碑,至今仍是该领域最重要的求解方法之一;
  • 内点法:通过选取可行域内部的点,沿下降方向不断迭代以逼近最优解,目前在理论上被认为是求解线性规划问题的最佳方法;
  • 启发式方法:基于经验准则通过不断迭代改进来搜索最优解,常见的包括贪心法、模拟退火算法、遗传算法以及神经网络等。

尽管不同的求解方法都旨在解决线性规划问题,最终结果殊途同归,但它们在核心思想上存在本质区别,导致具体的求解步骤和策略截然不同。

毫不夸张地说,对于许多初学者而言,是否学习过单纯形法,对其后续学习启发式方法几乎没有影响。

这揭示了什么?这意味着对于非数学专业的学生,或者旨在参加数学建模竞赛的学习者来说,针对每一类问题,完全没有必要掌握所有的解决方法。即便是数学专业的学生,在数学建模的学习周期内也不可能学会所有方法。

对于初学者,本文推荐选择较为通用且相对简单(思路清晰、代码简洁)的方法进行学习,无需盲目追求数量或新奇性。

1.2、线性规划的最快算法

那么,算法与方法有何不同?

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

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

在提出每种方法的基本思想和方案后,往往会出现许多变形、改进和发展的算法。极少数经过改进的算法具有实质性贡献并成为主流经典算法,即便如此,它们通常也仅带来性能或效率上的提升,对解决数学建模竞赛中的问题影响不大。

而绝大多数改进算法仅针对某些特殊情况或特定问题(自称)有效,常被用于大量发表学术论文。对于数学建模而言,学习基本算法或当前经典算法已足够,无需轻信那些自称具有优势的改进算法,那往往类似于“莆田系”广告般的夸大宣传。

存在一种例外情况,即某些算法具有特定的适用范围和限制条件。例如,内点法的基本算法无法处理等式约束,最短路径问题中的Dijkstra算法不能处理负权边。在这种情况下,如果选错算法,问题将无法求解。因此,对我们而言,明确算法的适用范围比深入理解算法本身更为重要。

回到本节标题,对于线性规划问题,什么算法是最快的呢?答案是:猜。并非让你随意猜测,而是指在求解线性规划问题时,“猜”起来可能比较快。这并非玩笑,而是严肃的观点。

佐治亚理工学院的彭泱教授在2021年计算机理论顶级会议SODA 2021上获得最佳论文奖(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 线性规划的资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表