scipy.optimize.

milp#

scipy.optimize.milp(c, *, integrality=None, bounds=None, constraints=None, options=None)[source]#

混合整数线性规划

求解以下形式的问题

\[\begin{split}\min_x \ & c^T x \\ \mbox{such that} \ & b_l \leq A x \leq b_u,\\ & l \leq x \leq u, \\ & x_i \in \mathbb{Z}, i \in X_i\end{split}\]

其中 \(x\) 是决策变量的向量; \(c\)\(b_l\)\(b_u\)\(l\), 和 \(u\) 是向量; \(A\) 是矩阵, \(X_i\) 是必须为整数的决策变量的索引集。(在这种情况下,只能取整数值的变量被称为“整数”变量;它具有“整型”约束。)

或者,也就是

最小化

c @ x

条件是

b_l <= A @ x <= b_u
l <= x <= u
Specified elements of x must be integers

默认情况下,l = 0u = np.inf,除非使用 bounds 指定。

参数:
c1D 稠密数组类

要最小化的线性目标函数的系数。 c 在求解问题之前被转换为双精度数组。

integrality1D 稠密数组类,可选

表示对每个决策变量的整型约束类型。

0 : 连续变量;无整型约束。

1 : 整数变量;决策变量必须是 bounds 内的整数。

2 : 半连续变量;决策变量必须在 bounds 内或取值 0

3 : 半整数变量;决策变量必须是 bounds 内的整数或取值 0

默认情况下,所有变量都是连续的。 integrality 在求解问题之前被转换为整数数组。

boundsscipy.optimize.Bounds,可选

决策变量的边界。下界和上界在求解问题之前被转换为双精度数组。 Bounds 对象的 keep_feasible 参数被忽略。如果未指定,则所有决策变量都约束为非负。

constraintsscipy.optimize.LinearConstraint 的序列,可选

优化问题的线性约束。参数可以是以下之一

  1. 单个 LinearConstraint 对象

  2. 可以转换为 LinearConstraint 对象的单个元组,如 LinearConstraint(*constraints)

  3. 完全由类型 1. 和 2. 对象组成的序列。

在求解问题之前,所有值都将转换为双精度,约束系数矩阵将转换为 scipy.sparse.csc_array 的实例。 LinearConstraint 对象的 keep_feasible 参数被忽略。

optionsdict,可选

求解器选项的字典。以下键被识别。

dispbool (默认值:False)

设置为 True,如果要将优化状态的指标在优化过程中打印到控制台。

node_limitint,可选

停止之前要解决的最大节点数(线性规划松弛)。默认值为无最大节点数。

presolvebool (默认值:True)

预求解尝试在将问题发送到主求解器之前识别出琐碎的不可行性、识别出琐碎的无界性,并简化问题。

time_limitfloat,可选

分配给求解问题的时间上限(以秒为单位)。默认值为无时间限制。

mip_rel_gapfloat,可选

MIP 求解器的终止条件:当原始目标值与对偶目标边界的差距(按原始目标值缩放)<= mip_rel_gap 时,求解器将终止。

返回值:
resOptimizeResult

scipy.optimize.OptimizeResult 的实例。该对象保证具有以下属性。

statusint

表示算法退出状态的整数。

0 : 找到最优解。

1 : 达到迭代次数或时间限制。

2 : 问题不可行。

3 : 问题无界。

4 : 其他;请参见消息以获取详细信息。

successbool

找到最优解时为 True,否则为 False

messagestr

算法退出状态的字符串描述符。

以下属性也将存在,但值可能是 None,具体取决于解决方案状态。

xndarray

使目标函数在满足约束条件的情况下最小化的决策变量的值。

funfloat

目标函数 c @ x 的最优值。

mip_node_countint

MILP 求解器求解的子问题或“节点”数量。

mip_dual_boundfloat

MILP 求解器对最优解下界的最终估计。

mip_gapfloat

原始目标值与对偶目标边界之间的差值,按原始目标值缩放。

备注

milp 是 HiGHS 线性优化软件 [1] 的包装器。该算法是确定性的,它通常会找到中等难度的混合整数线性规划的全局最优解(如果存在)。

参考文献

[1]

Huangfu, Q.,Galabova, I.,Feldmeier, M.,and Hall, J. A. J. “HiGHS - 高性能线性优化软件。” https://highs.dev/

[2]

Huangfu, Q. and Hall, J. A. J. “并行化对偶修正单纯形法。” 数学规划计算,10 (1),119-142,2018。DOI: 10.1007/s12532-017-0130-5

示例

考虑 https://en.wikipedia.org/wiki/Integer_programming#Example 中的问题,该问题表示为两个变量的最大化问题。由于 milp 要求将问题表示为最小化问题,因此决策变量上的目标函数系数为

>>> import numpy as np
>>> c = -np.array([0, 1])

请注意负号:我们通过最小化目标函数的负值来最大化原始目标函数。

我们将约束条件的系数收集到像这样的数组中

>>> A = np.array([[-1, 1], [3, 2], [2, 3]])
>>> b_u = np.array([1, 12, 12])
>>> b_l = np.full_like(b_u, -np.inf, dtype=float)

由于这些约束没有下限,我们定义了一个名为 b_l 的变量,其中充满了表示负无穷大的值。这对于 scipy.optimize.linprog 的用户来说可能不熟悉,因为它只接受形式为 A_ub @ x <= b_u 的“小于”(或“上限”)不等式约束。通过接受约束 b_l <= A_ub @ x <= b_ub_lb_umilp 使得用简洁的方式指定“大于”不等式约束、“小于”不等式约束和等式约束变得容易。

这些数组被收集到一个单独的 LinearConstraint 对象中,例如

>>> from scipy.optimize import LinearConstraint
>>> constraints = LinearConstraint(A, b_l, b_u)

决策变量的非负性边界默认情况下会被强制执行,因此我们不需要为 bounds 提供参数。

最后,问题说明两个决策变量都必须是整数

>>> integrality = np.ones_like(c)

我们像这样解决问题

>>> from scipy.optimize import milp
>>> res = milp(c=c, constraints=constraints, integrality=integrality)
>>> res.x
[2.0, 2.0]

请注意,如果我们解决了松弛问题(没有整数约束)

>>> res = milp(c=c, constraints=constraints)  # OR:
>>> # from scipy.optimize import linprog; res = linprog(c, A, b_u)
>>> res.x
[1.8, 2.8]

我们将无法通过四舍五入到最接近的整数来获得正确的解。

其他例子在 教程中 给出。