#线性规划 #求解器 #优化 #API 绑定 #符号数学

good_lp

为 Rust 提供混合整数线性规划,具有用户友好的 API。该软件包允许建模 LP 问题,并使用各种求解器解决它们。

51 个版本 (21 个稳定版)

1.8.1 2024 年 4 月 4 日
1.7.0 2023 年 10 月 6 日
1.4.1 2023 年 7 月 18 日
1.4.0 2023 年 3 月 12 日
0.4.3 2021 年 3 月 19 日

#16 in 数学

Download history 6118/week @ 2024-04-18 5922/week @ 2024-04-25 10666/week @ 2024-05-02 4547/week @ 2024-05-09 6341/week @ 2024-05-16 6318/week @ 2024-05-23 6777/week @ 2024-05-30 5841/week @ 2024-06-06 7927/week @ 2024-06-13 8594/week @ 2024-06-20 7398/week @ 2024-06-27 6372/week @ 2024-07-04 6202/week @ 2024-07-11 5703/week @ 2024-07-18 7241/week @ 2024-07-25 8725/week @ 2024-08-01

每月下载量 28,825
50 软件包中使用 (6 个直接使用)

MIT 许可证

135KB
2.5K SLoC

good_lp

一个易于使用、性能优异且类型良好的混合整数线性规划模型器。

Crates.io documentation MIT license

use std::error::Error;

use good_lp::{constraint, default_solver, Solution, SolverModel, variables};

fn main() -> Result<(), Box<dyn Error>> {
    variables! {
        vars:
               a <= 1;
          2 <= b <= 4;
    } // variables can also be added dynamically
    let solution = vars.maximise(10 * (a - b / 5) - b)
        .using(default_solver) // multiple solvers available
        .with(constraint!(a + 2 <= b))
        .with(constraint!(1 + a >= 4 - b))
        .solve()?;
    println!("a={}   b={}", solution.value(a), solution.value(b));
    println!("a + b = {}", solution.eval(a + b));
    Ok(())
}

特性和限制

  • 线性规划。该软件包目前仅支持线性规划的定义。不能与二次函数一起使用。例如:可以最大化 3 * x + y,但不能最大化 3 * x * y
  • 连续和整数变量。good_lp 本身支持混合整数线性规划(MILP),但并非所有底层求解器都支持整数变量。(参见 变量类型
  • 非求解器。该软件包使用其他 Rust 软件包提供求解器。good_lp 本身没有求解算法。如果遇到求解器问题,请直接向求解器报告。以下为支持的求解器列表。

贡献

欢迎拉取请求!如果您需要尚未实现的功能,请与我们联系。还可以毫不犹豫地提出问题以讨论实现。

替代方案

如果您需要非线性规划,可以使用 lp-modeler。然而,它目前在大规模问题上非常慢。

如果您不需要使用 Rust 习惯用法表达目标函数和约束条件,也可以直接使用底层求解器库,例如 coin_cbcminilp

使用示例

您可以在 resource_allocation_problem.rs 中找到资源分配问题的示例。

求解器

这个库为多个求解器提供抽象。默认情况下,它使用cbc,但您也可以使用cargo特性激活其他求解器。

求解器特性名称 整数变量 没有C编译器* 没有额外库** 快速
coin_cbc
highs ✅+
lpsolve
minilp
lp-solvers
scip
cplex-rs ✅++
clarabel
  • * 没有C编译器:仅使用cargo构建,无需安装C编译器
  • ** 没有额外库:运行时无需额外库,所有依赖项都是静态链接的
  • + highs自身是静态链接的,无需手动安装。但是,在某些系统上,您可能需要安装highs自身的依赖项
  • ++ cplex_rs包静态链接到本地安装的IBM ILOG CPLEX Optimizer。

要使用替代求解器,请在您的Cargo.toml中放入以下内容

good_lp = { version = "*", features = ["your solver feature name"], default-features = false }

请注意,lpsolvecplex-rs特性是互斥的,同时激活它们将导致编译错误。特别是,这意味着使用--all-features选项构建将产生编译错误。

cbc

默认使用,性能良好,但需要在构建机器上提供cbc C库头文件,并在您想要运行程序的任何机器上提供cbc动态库。

在Ubuntu上,您可以使用以下命令安装

sudo apt-get install coinor-cbc coinor-libcbc-dev

在MacOS上,使用homebrew

brew install cbc

如果您禁用了此crate的默认特性并手动激活cbc特性,请小心。在这种情况下,您还必须激活singlethread-cbc,除非您使用CBC_THREAD_SAFE选项自己编译了Cbc。否则,使用多线程的Cbc将是不安全的。

minilp

minilp是一个纯Rust求解器,这意味着它无需安装任何其他内容即可直接使用。

Minilp是用纯Rust编写的,因此您可以在不安装C编译器或任何外部库的情况下使用它,但它的速度比其他求解器慢。

在调试模式下编译时表现非常差,因此当解决大型问题时,请务必以--release模式编译您的代码。

HiGHS

HiGHS是一个免费(MIT)的并行混合整数线性规划求解器,用C++编写。它能够充分利用所有可用的处理器核心来解决一个问题。

good_lp使用highs crate来调用HiGHS。您需要C编译器,但在Linux上您不需要安装任何额外的库(它仅依赖于C++标准库)。更多信息请参阅highs-sys crate

lpsolve

lp_solve是一个免费(LGPL)的基于改进单纯形法的线性(整数)规划求解器,用C编写。

good_lp使用lpsolve crate来调用lpsolve。您需要C编译器,但不需要安装任何额外的库。

lp-solvers

lp-solvers特性特别之处在于它不包含任何求解器。相反,它在运行时调用其他求解器。它将给定的问题写入一个.lp文件,并启动外部求解器命令(如gurobicplexcbcglpk)来解决问题。

此方法存在一些开销:将问题写入文件、启动外部求解器、等待其完成,然后解析其解可能需要几百毫秒。如果您不是解决几个大问题,而是解决许多小问题(例如在Web服务器中),则此方法可能不合适。

此外,您的程序最终用户将必须自行安装所需的求解器。

SCIP

SCIP是目前最快的开源混合整数规划(MIP)和混合整数非线性规划(MINLP)求解器之一。它也是一个约束整数规划和分支切割定价的框架。它允许对求解过程进行完全控制,并访问求解器内部的详细信息。

good_lp通过其Rust接口russcip使用SCIP。要使用此功能,您需要安装SCIP。最简单的方法是从此处安装预编译包或通过运行

conda install --channel conda-forge scip

cplex-rs

IBM ILOG CPLEX Optimizer是一款商业高性能优化求解器,适用于线性、混合整数和二次规划。

good_lp使用cplex-rs crate通过安全的Rust绑定调用CPLEX,而后者又通过cplex-rs-sys crate调用CPLEX C API的原始绑定。

要使用此功能,您需要一个有效的CPLEX安装。CPLEX应安装在其默认安装目录中,或者您也可以在编译时通过CPLEX_PATH环境变量指定其安装目录

由于cplex-rs-sys使用bindgen生成原始C绑定,因此您还需要安装clang和llvm,如bindgen要求中所示。

Clarabel

Clarabel是由Oxford Control组用Rust编写的免费(Apache 2.0许可协议)线性规划求解器。

它不支持整数变量,但速度快,易于安装。它实现了SolutionWithDual特质,允许您访问约束的影子价格(对偶值)。

变量类型

good_lp内部将所有变量值和系数表示为f64。它允许您使用f64i32(在后一种情况下,整数将无损转换为浮点数)来表示约束。解的值也是f64

例如

// Correct use of f64 and i32 for Variable struct and constraints
  variables! {
    problem:
      a <= 10.0;
      2 <= b <= 4;
  };
  let model = problem
    .maximise(b)
    .using(default_solver)
    .with(constraint!(a + 2 <= b))
    .with(constraint!(1 + a >= 4.0 - b));

在此,abVariable实例,可以取连续(浮点)或整数值。约束可以使用f64i32表示,如示例所示(但将例如4.0替换为usize变量将失败,因为usize无法无损转换为f64)。

解决方案的值始终是 f64 类型,无论变量是否定义为 f64i32。因此,即使您使用整数变量,解决方案对象也将存储整数变量的值作为 f64

例如,当打印解决方案时

// Correct use of f64 for solution values
println!("a={}   b={}", solution.value(a), solution.value(b));
println!("a + b = {}", solution.eval(a + b));

// Incorrect use of i32 in combination with solution value (Will fail!)
println!("a + 1 = {}", solution.value(a) + 1); // This will cause a compilation error!

调用 solution.value(a)solution.value(b) 将返回 f64 类型的值,而 solution.eval(a + b) 也将提供一个 f64 类型的值。

许可证

本库在 MIT 许可下发布。求解器本身有不同的许可证,请参阅它们的个别文档。

依赖项

~0–11MB
~116K SLoC