【Python】lpsolve_wrapper——线性规划求解器Lpsolve的Python高级Api包装类

Lpsolve是一个跨平台的开源混合整数线性规划(MILP)求解器,提供了Python Api。
http://web.mit.edu/lpsolve/doc/Python.htm

lpsolve_wrapper是lp_solve的python包装类,提供了基于变量的Api。
https://github.com/hangvane/lpsolve_wrapper

目录

  • 动机
  • lpsolve_wrapper
    • 特性
    • 安装
    • 教程


动机

Lpsolve虽提供了Python Api,但Lpsolve的Python Api无法管理变量(特别是包含多个值的变量集,如 x i , j x_{i,j} xi,j),也无法对每个变量的系数矩阵自动压平为1维、自动拼接多个变量、得到的最优变量取值也不会自动按变量切割、反压平为单个变量的对应shape。目前使用Lpsolve的常见代码类似于:

from lp_maker import lp_maker, lpsolve
import numpy as np

x = np.ones((2, 2))
y = np.ones((3, 3))

f = np.concatenate([x.ravel(), y.ravel()]).tolist()

x.fill(0)
y.fill(0)
for i in range(2):
    x[0][i] = 1

for n in range(3):
    y[0][n] = 1
A = [np.concatenate([x.ravel(), y.ravel()]).tolist()]
b = 5
e = [-1, ]

x.fill(0)
y.fill(0)
vlb = np.concatenate([x.ravel(), y.ravel()]).tolist()
x.fill(1)
y.fill(2)
vub = np.concatenate([x.ravel(), y.ravel()]).tolist()
xint = []
scalemode = 1
setminimium = 0

lp = lp_maker(f, A, b, e, vlb, vub, xint, scalemode, setminimium)
lpsolve('solve', lp)
obj = lpsolve('get_objective', lp)
raw_notation = lpsolve('get_variables', lp)[0]

print('objective:', obj)
offset = 0
print('x:', raw_notation[0:2 * 2])
offset += 2 * 2
print('y:', raw_notation[offset + 1:offset + 3 * 3])


需要反复进行细节确认,目前只有2个小规模变量就乱成一团,大规模线性规划就是在写一坨屎山,而且最后得到的目标变量取值还没有反压平reshape。且在写以上demo时我出现了4个bug,全部和numpy结合lpsolve,以及lpsolve提供的接口细节相关,编码效率极低。


lpsolve_wrapper

lpsolve_wrapper是lp_solve的python包装类,提供了基于变量的Api。


特性

  • 支持变量管理
  • 自动偏移管理
  • 自动压平/反压平
  • 支持多种约束添加方式
  • 支持Python 2.x/3.x

安装

强烈推荐通过 conda 安装 lpsolve

conda install -c rmg lpsolve55

如果你是windows用户,可以前往
https://www.lfd.uci.edu/~gohlke/pythonlibs/#lp_solve
下载编译好的 .whl 包,并通过pip离线安装:

pip install the_name_of_lpsolve55.whl

然后将 lpsolve_wrapper.py 添加到你的项目中。


教程

这里提供了几个例子,可以基于这些例子创建更复杂的线性规划,一个简单的例子如下:

  1. 引入 lpsolve_wrapper
import lpsolve_wrapper as lw
  1. 创建求解器实例,并添加两个变量:
model = lw.Model(
    notations={
     
        'x': lw.notation(
            lower_bound=0,
        ),
        'y': lw.notation(
            lower_bound=0,
        )
    })
  1. 调用 lpsolve_wrapper 中的方法添加约束和求解:
model.add_constr(
    coefs=[
        lw.coef('x', 1),
        lw.coef('y', 1),
    ],
    right_value=75,
    constr_type=lw.LEQ
)
objective, notation_list = model.lp_solve(
    obj_func={
     
        'x': 143,
        'y': 60,
    },
    minimize=False
)
print('objective:', objective)
print('x:', notation_list['x'])
print('y:', notation_list['y'])

lpsolve_wrapper 提供了3个方法来添加约束:

  1. 通过给单个变量赋值的方式:
model.add_constr(
    coefs=[
        lw.coef(name='x', idx=[2, 3], value=1),
        lw.coef(name='y', idx=[0], value=2),
    ],
    right_value=75,
    constr_type=lw.GEQ
)
  1. 通过输入变量系数矩阵的方式:
model.add_constr_mat(
    coef_mats={
     
        'x': [1, 1, 1],
        'y': [[1, 2], [3, 4]]
    },
    right_value=1,
    constr_type=lw.EQ
)
  1. 通过传入回调函数的方式:
def tmp_func(y):
    y[2][3] = 1


model.add_constr_callback(
    callbacks={
     
        'x': lambda x: x[0].fill(1),
        'y': tmp_func

    },
    right_value=1,
    constr_type=lw.EQ,
)

还有若干用例和用例的公式表述可供参考。

- add_constr() add_constr_mat() add_constr_callback()
用例 0
用例 1
用例 2
用例 3
用例 4
用例 5

你可能感兴趣的:(Python,python,ilp,线性规划)