HiGHS 线性优化求解器实战指南:从建模、求解到读懂 MIP 结果
【免费下载链接】HiGHSLinear optimization software项目地址: https://gitcode.com/GitHub_Trending/hi/HiGHS
凌晨两点,你盯着那张排了三天产线的调度表:变量上万、约束十几万,之前用的工具跑到一半内存爆掉,或者干脆给了个"时间超限"。如果你正被这类"模型太大算不动"的卡点缠住,HiGHS 值得你花十分钟认识一下——它是一款开源的线性优化求解器,核心用 C++ 编写,同一套内核同时覆盖线性规划(LP)、二次规划(QP)和混合整数规划(MIP),并提供 Python、C、Fortran、C# 等多语言接口。这篇文章不讲概念堆砌,按你实际动手的顺序来:先装上,再用一道生产计划题完整走一遍,回头才去理解它内部到底用了哪些算法,最后给你一套让它更快更稳的调法。
HiGHS 是什么,以及它适不适合你的题
一句话定位:HiGHS 是一个"什么规模的规划题都能接"的开源优化求解器。
它适合的场景:
- 纯连续变量的 LP(产能分配、配比、网络流);
- 带整数/0-1 变量的 MIP(排班、选址、投诚-下不为例的投资组合离散化);
- 目标函数里出现变量乘积的凸 QP(组合优化、最二次调节);
- 你已有
.mps或.lp格式模型文件,想换个更快的引擎重算。
也要说清楚它的边界:HiGHS 不处理非凸 QP(Hessian 必须半正定),也不是通用的非线性规划(NLP)求解器——如果约束里有三角函数、指数这类一般非线性,得另找工具。另外它不内置建模语言生态(像 PuLP、Pyomo 那种高层建模),模型本身还是要你自己用数组或变量表达式搭起来,但它对稀疏矩阵的处理效率正是为此优化的。
先让它跑起来:pip 一条命令 vs 源码编译
快速安装 highspy
大多数读者的正确入口是 Python 包highspy,一条命令搞定,不用碰编译器:
pip install highspy装完别急着写模型,先做版本自检(这也是后续排查"版本不对"的基线):
import highspy print(highspy.HIGHS_VERSION_MAJOR, highspy.HIGHS_VERSION_MINOR, highspy.HIGHS_VERSION_PATCH)能打印出三个整数(例如 1 15 1,对应仓库里的 Version.txt)就说明内核加载正常。
源码编译:什么时候才需要
只有两种情况值得走这条路:你要把 HiGHS 链进自己的 C++/C 工程,或者需要启用 HiPO 内点法这类可选项。HiGHS 用 CMake 构建,要求CMake 3.15+、编译器支持C++11(见 CMakeLists.txt):
git clone https://gitcode.com/GitHub_Trending/hi/HiGHS cd HiGHS cmake -S . -B build -DCMAKE_BUILD_TYPE=Release cmake --build build --parallel 4注意这里:CMake 配置阶段拒绝在源码目录内构建(in-source build 会直接报错),必须像上面这样指定独立的build目录,第一次跑就报这个错的人不在少数。更多平台细节可翻 安装文档。
拿一道题完整走一遍:生产计划建模
光装不算会用。用两小时把下面这道题敲完,你对 highspy 的手感就有了。
题面:工厂生产 A、B 两种产品。A 单件利润 30 元,B 单件 25 元;每件 A 占 1 个工时、B 占 2 个工时,日工时上限 180;两种产品共用一条原材料线,合计日产量不超过 120 件;A 日产能上限 100 件、B 上限 150 件。求利润最大的产量组合。
建模到出结果,整个流程就是"建变量 → 加约束 → 定目标 → 求解 → 取数"五步:
import highspy h = highspy.Highs() # 1. 决策变量(含上下界) x_a = h.addVariable(lb=0, ub=100) # 产品 A 产量 x_b = h.addVariable(lb=0, ub=150) # 产品 B 产量 # 2. 资源约束:工时 + 原材料 h.addConstrs(x_a + 2 * x_b <= 180, x_a + x_b <= 120) # 3. 目标函数:最大化利润 h.maximize(30 * x_a + 25 * x_b) # 4. 求解 h.run() # 5. 读取结果 print(h.modelStatusToString(h.getModelStatus())) # 应输出 optimal print("最优利润:", h.getInfo().objective_function_value) print("A 产量:", h.variableValue(x_a)) print("B 产量:", h.variableValue(x_b))跑完你会发现:getModelStatus()告诉你"最优/不可行/无界"三态之一,getInfo()里能拿到目标值、迭代次数、求解时间这些运行信息,单个变量的取值用variableValue()直接读。最偷懒的路径其实是readModel()——如果模型已经是文件,一行h.readModel("check/instances/avgas.mps")就能读入仓库自带的那道经典汽油调配题(avgas.mps),然后照样run()。
想上 MIP 也几乎不用换姿势,建变量时多一个参数把类型改成整数即可:
x = h.addVariable(lb=0, ub=10, type=highspy.HighsVarType.kInteger)更多官方写法可以对着 examples/ 里的minimal.py、call_highs_from_python.py逐行看,那几段就是本小节代码的直接出处。
它内部到底怎么算:四把刀,各管一段
看完上面的用法再回头看内核,理解会顺很多。HiGHS 默认策略是solver = choose,它会按题型自动选算法,但你知道"刀"在哪,才能在自己慢的场景下手干预。
- 单纯形法(highs/simplex/):HiGHS 的原生主力,默认跑对偶单纯形,因为它比原始单纯形更快也更稳。中小规模、结构一般的 LP,它就是答案;需要整数解时,MIP 的每个节点上解的松弛也是它。
- 内点法(highs/ipm/):仓库里带了两套——IPX(预条件共轭梯度类,串行)和 HiPO(并行内点,需要 BLAS 支持)。大规模、超稀疏的问题上内点法常常几十次迭代就收敛,是"题大但连续"时的选择。
- 分支定界 MIP(highs/mip/):整数问题没有捷径,HiGHS 靠预处理收缩问题 + 分支定界 + 割平面(冲突池、割池、Modk 割等一整套分离器)推进。你看到的 MIP 耗时,99% 花在这里。
- 预处理 presolve(highs/presolve/):所有算法跑之前先过一遍——固定松弛变量、删冗余约束、收紧界。这是默认开启的"免费加速",别手动关它,除非你在做数值实验。
对照着 求解器文档看更细的分法:QP 走主动集法(highs/qpsolver/),MIP 用分支定界,LP 按规模在单纯形与内点之间切换。经验法则一句话:千级变量以下随便用默认;几万变量以上的稀疏连续题,把内点法放进候选。
让它更快更稳:三个旋钮和两个高阶开关
参数文件与关键选项
调优的入口是选项(完整清单在 options 定义文档,格式示例见 sample_options_file)。Python 里逐项设:
h.setOptionValue("presolve", "choose") # 预处理 h.setOptionValue("parallel", "choose") # 并行 h.setOptionValue("threads", 0) # 0 = 自动定线程数 h.setOptionValue("time_limit", 3600.0) # 限时 1 小时写成文件的话就是每行一个选项 = 值,C++ 侧可以整体传入。三个真正影响速度的旋钮:
presolve:确认它是on或choose,别图省事关成off;parallel/threads:MIP 是多线程受益最大的场景,先放开让它跑,再按机器核数收敛threads;time_limit:生产调度类任务给求解器设时限,超时后 HiGHS 会返回当前最优整数解,比干等强。
两个容易漏掉的高阶开关
多目标:当"利润最大"和"工时最省"互相打架时,HiGHS 支持加权多目标,用法可参考仓库里的 multi_objective.py 和 multiple_objective.py,思路都是给每个目标定权重再合成求解。
敏感性分析(ranging):想知道"利润 30 元降到多少才会换生产方案",打开这个开关:
h.setOptionValue("ranging", "on") h.run() status, ranging = h.getRanging()ranging会给出目标系数、变量界、约束右端项各自的变化区间,以及最优基保持不变的范围——做方案稳健性判断时直接省掉反复重算。
卡住了?这样排查
cmake一跑就报 in-source build 或版本错误?两件事挨个查:CMake 是否 ≥ 3.15;-B build这个输出目录参数是不是漏了。HiGHS 明确禁止在源码目录里直接编译,报错信息本身就是提示。
编译到一半报一堆语法错误?十有八九是编译器没吃到 C++11。确认编译选项里有-std=c++11以上(项目默认就是 C++11,见 CMakeLists.txt 的CMAKE_CXX_STANDARD)。
LP 秒回,MIP 半小时没影?这是正常现象,不是坏了——整数问题本质上就是这么贵。能做的:确认 presolve 没被关;把parallel放开;把"明显是整数"的变量都标成整数而不是只标一部分,让 presolve 有更多压缩空间。实在不行就time_limit兜底拿次优解。
求解报 infeasible(不可行)?先用最小变量集复现,再逐条注释约束定位是哪几条互相打架;仓库的check/instances/里就备了infeasible-mip0.mps这类专门用于调试不可行的样例。HiGHS 也内置 IIS(不可行不可约子集)能力,见 HighsIis.h,能帮你从上万条约束里揪出真正冲突的那几行。
想用 HiPO 但链接报错?HiPO 依赖 BLAS,这是 HiGHS 少有的外部要求:Linux 上apt install libopenblas-dev后加-DHIPO=ON重新配置,细节见 安装文档。
下一步往哪走
- 想啃内核:入口就一个头文件,highs/Highs.h,API 注释相当完整;
- 想看真实模型:check/instances/ 里从 8 变量的
avgas.mps到几千变量的网络流都有,拿来就能readModel()练手; - 要读设计文档:docs/src/ 下的 solvers、parallel、installation 三篇优先,再按兴趣进 guide;
- 学习路线建议:先用
minimal.py建立手感 → 挑一道check/instances/的 MPS 题跑通读取流程 → 再给自己的题加整数变量,体会 MIP 的耗时从哪来 → 最后才去碰 presolve 和选项细节。
跑通第一个 MIP 那天你会发现,所谓"求解器选型"其实没那么玄:模型写对、presolve 开着、时限设好,HiGHS 的默认策略已经替你做了大部分决策。剩下的,就是把它嵌进你的排产或调度系统里,让它替你把凌晨两点的活干了。
【免费下载链接】HiGHSLinear optimization software项目地址: https://gitcode.com/GitHub_Trending/hi/HiGHS
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考