Ваша проблема, по сути, является линейной, и поэтому она идеально подходит для подхода линейного программирования. Тем не менее, вы даете его решателю, не имея ни малейшего понятия о линейности проблемы, так что он непременно найдет это хитрым: он в значительной степени должен попробовать каждую возможность, которая займет много времени. Возможно, можно переписать ваши ограничения в различные формы для решателя python-constraint
(например, он имеет форму ограничения MaxSumConstraint
), который может работать лучше, но в идеале я думаю, что вы должны использовать решатель, специализированный для линейных задач.
Есть решатель по имени kiwisolver
, который будет делать то, что вы хотите. Вот ваш пример, преобразованный для этой библиотеки:
import kiwisolver
x1 = kiwisolver.Variable('x1')
x2 = kiwisolver.Variable('x2')
x3 = kiwisolver.Variable('x3')
x4 = kiwisolver.Variable('x4')
constraints = [1995 <= 2*x1 + 4*x2 + 3*x3 + x4,
2*x1 + 4*x2 + 3*x3 + x4 <= 2000,
x1 >= 1.2*x2,
x2 >= 1.3*x3,
x3 >= 1.1*x4,
x4 >= 0]
solver = kiwisolver.Solver()
for cn in constraints:
solver.addConstraint(cn)
for x in [x1, x2, x3, x4]:
print(x.value())
, что дает
254.49152542372883
212.07627118644066
163.13559322033896
148.30508474576254
Но вы также можете использовать стандартный линейный решатель программ, такой как scipy. Вам просто нужно преобразовать свое неравенство в правильную форму.
Вы хотите:
1. 1995 < 2*x1 + 4*x2 + 3*x3 + x4 < 2000
2. x1 >= 1.2*x2
3. x2 >= 1.3*x3
4. x3 >= 1.1*x4
5. x4 > 0.0
Итак, мы переписали это на:
2*x1 + 4*x2 + 3*x3 + 1*x4 < 2000
-2*x1 + -4*x2 + -3*x3 + -1*x4 < -1995
-1*x1 + 1.2*x2 + 0*x3 + 0*x4 < 0
0*x1 + -1*x2 + 1.3*x3 + 0*x4 < 0
0*x1 + 0*x2 + -1*x3 + 1.1*x4 < 0
Вы можете добавить границы для x1
к x4
, как вы упомянули в вопросе, но по умолчанию они будут просто неотрицательными. Итак, для LP нам также нужно выбрать, где в политопе возможных решений мы хотим оптимизировать: в этом случае я просто выберу решение с минимальной суммой. Это дает нам следующее:
from scipy.optimize import linprog
output = linprog([1, 1, 1, 1],
[[ 2, 4, 3, 1],
[-2, -4, -3, -1],
[-1, 1.2, 0, 0],
[0, -1, 1.3, 0],
[0, 0, -1, 1.1]],
[2000, -1995, 0, 0, 0])
print(output.x)
Это дает
[274.92932862 229.10777385 176.23674912 0. ]
, который является оптимальным решением для LP. Обратите внимание, что он сделал x4 = 0
: LP обычно не различают >
и >=
, и поэтому у нас есть решение, где x4
- ноль, а не крошечный эпсилон больше нуля.
Наконец, обратите внимание, что проблема сильно ограничена: мы можем выбрать совершенно другое решение, изменив цель. Вот решение, в котором мы просим linprog
максимизировать 2*x1 + 4*x2 + 3*x3 + x4
:
from scipy.optimize import linprog
output = linprog([-2, -4, -3, -1],
[[ 2, 4, 3, 1],
[-2, -4, -3, -1],
[-1, 1.2, 0, 0],
[0, -1, 1.3, 0],
[0, 0, -1, 1.1]],
[2000, -1995, 0, 0, 0])
print(output.x)
1039 * дает *
[255.1293488 212.60779066 163.54445436 148.67677669]