Альтернативы lpsolve в Python для быстрой настройки и решения - PullRequest
0 голосов
/ 24 апреля 2019

Я давно пользуюсь lpsolve в Python, и в целом получаю хорошие результаты.Я даже написал свою собственную оболочку Cython, чтобы преодолеть беспорядок, который есть у оригинальной оболочки Python.

Моя оболочка Cython намного быстрее в установке проблемы, но, конечно, время решения зависит только от кода lpsolve C и не имеет ничего общего с Python.

Я толькорешение реальных линейных задач, без MIP.Самый последний (и один из самых больших) LP, который мне приходилось решать, имел матрицу ограничений размером около 5000 x 3000, а для установки и решения требуется около 150 мс.Проблема в том, что я должен решить слегка измененную версию одной и той же проблемы много раз в моем моделировании (ограничения, RHS, границы и т. Д. Зависят от времени для моделирования с большим количеством временных шагов).Матрица ограничений обычно очень разреженная, примерно 0,1% - 0,5% от NNZ или меньше.

Используя lpsolve, установка и решение проблемы так же просты, как следующие:

import numpy
from lp_solve.lp_solve import PRESOLVE_COLS, PRESOLVE_ROWS, PRESOLVE_LINDEP, PRESOLVE_NONE, SCALE_DYNUPDATE, lpsolve

# The constraint_matrix id a 2D NumPy array  and it contains 
# both equality and inequality constraints
# And I need it to be single precision floating point, like all 
# other NumPy arrays from here onwards
m, n = constraint_matrix.shape

n_le = len(inequality_constraints)
n_e  = len(equality_constraints)

# Setup RHS vector
b = numpy.zeros((m, ), dtype=numpy.float32)

# Assign equality and inequality constraints (= and <=)
b[0:n_e]  = equality_constraints
b[-n_le:] = inequality_constraints

# Tell lpsolve which rows are equalities and which are inequalities
e = numpy.asarray(['LE']*m)
e[0:-n_le] = 'EQ'

# Make the LP
lp = lpsolve('make_lp', m, n)

# Some options for scaling the problem
lpsolve('set_scaling', lp, SCALE_DYNUPDATE)
lpsolve('set_verbose', lp, 'IMPORTANT')

# Use presolve as it is much faster
lpsolve('set_presolve', lp, PRESOLVE_COLS | PRESOLVE_ROWS | PRESOLVE_LINDEP)

# I only care about maximization
lpsolve('set_sense', lp, True)

# Set the objective function of the problem
lpsolve('set_obj_fn', lp, objective_function)
lpsolve('set_mat', lp, constraint_matrix)

# Tell lpsolve about the RHS
lpsolve('set_rh_vec', lp, b)

# Set the constraint type (equality or inequality)
lpsolve('set_constr_type', lp, e)

# Set upper bounds for variables - lower bounds are automatically 0
lpsolve('set_upbo', lp, ub_values)

# Solve the problem
out = lpsolve('solve', lp)

# Retrieve the solution for all the variables
vars_sol = numpy.asarray([lpsolve('get_var_primalresult', lp, i) for i in xrange(m + 1, m + n + 1)], dtype=numpy.float32)

# Delete the problem, timestep done
lpsolve('delete_lp', lp)

По причинам, которые слишком длинны для объяснения, мои массивы NumPy представляют собой все массивы с плавающей запятой одинарной точности, и я бы хотел, чтобы они остались такими.

Теперь, после всего этогоболезненное введение, я хотел бы спросить: кто-нибудь знает другую библиотеку (с разумными обертками Python), которая позволяет мне устанавливать и решать проблему такого размера так же быстро (или потенциально быстрее), чем lpsolve?Большинство библиотек, на которые я смотрел (PuLP, CyLP, PyGLPK и т. Д.), Похоже, не имеют прямого способа сказать: «Это вся моя матрица ограничений, установите ее за один раз».Похоже, что они в основном ориентированы на то, чтобы быть «языками моделирования», которые допускают такие причудливые вещи (пример CyLP):

# Add variables
x = s.addVariable('x', 3)
y = s.addVariable('y', 2)

# Create coefficients and bounds
A = np.matrix([[1., 2., 0],[1., 0, 1.]])
B = np.matrix([[1., 0, 0], [0, 0, 1.]])
D = np.matrix([[1., 2.],[0, 1]])
a = CyLPArray([5, 2.5])
b = CyLPArray([4.2, 3])
x_u= CyLPArray([2., 3.5])

# Add constraints
s += A * x <= a
s += 2 <= B * x + D * y <= b
s += y >= 0
s += 1.1 <= x[1:3] <= x_u

Мне, честно говоря, наплевать на гибкость, мне просто нужна грубая скорость в проблеменастроить и решить.Создание матриц NumPy и выполнение всех вышеперечисленных операций определенно приведет к снижению производительности.

Я бы предпочел остаться на решателях с открытым исходным кодом, если это возможно, но любые предложения приветствуются.Мои извинения за длинный пост.

Андреа.

...