Я пытаюсь написать скрипт Python, который решает заданную систему четырех неравенств с тремя переменными:
х * 31 + y * 2.9 + z * 25 <= 160
x * 0 + y * 23 + z * 1.3 <= 160
x * 3.6 + y * 0.9 + z * 33 <= 50
x * 165 + y * 110.9 + z * 402 <= 1730
До сих пор я придумал следующий код:
from sympy.abc import x, y, z
from sympy import solve_rational_inequalities, Poly
a = solve_rational_inequalities([
((Poly(31*x + 2.9*y + 25*z), Poly(1)), '<=', Poly(160)),
((Poly(x), Poly(23*y), Poly(1.3*z), Poly(0)), '<=', Poly(160)),
((Poly(3.6*x), Poly(0.9*y), Poly(33*z), Poly(0)), '<=', Poly(50)),
((Poly(165*x), Poly(110.9*y), Poly(402*z), Poly(0)), '<=', Poly(1730))
])
print(a)
После выполнения я получаю:
Traceback (most recent call last):
File "/home/main.py", line 5, in <module>
((Poly(31*x + 2.9*y + 25*z), Poly(1)), '<=', Poly(160)),
File "/usr/lib/python3/dist-packages/sympy/polys/polytools.py", line 164, in __new__
return cls._from_expr(rep, opt)
File "/usr/lib/python3/dist-packages/sympy/polys/polytools.py", line 294, in _from_expr
return cls._from_dict(rep, opt)
File "/usr/lib/python3/dist-packages/sympy/polys/polytools.py", line 231, in _from_dict
raise GeneratorsNeeded(sympy.polys.polyerrors.GeneratorsNeeded:
can't initialize from 'dict' without generators
В чем может быть проблема, и как ее можно исправить? Кроме того, есть ли лучшая библиотека для решения таких проблем?
На первый взгляд, у системы неравенств может не быть единственного решения, поэтому, может быть, вам нужна характеристика выпуклой оболочки точек, удовлетворяющих неравенствам? или на картинке есть целевая функция, которую вы хотите минимизировать или максимизировать? Выглядит как интересная проблема, но, возможно, вы могли бы рассказать больше о том, что вы подразумеваете под словом «решить» в этом контексте.
@RobertDodier Контекст таков, что я хочу найти все комбинации целых чисел X, Y, Z, которые удовлетворяют неравенствам. Кроме того, такие коэффициенты, как 31, 2,9, 25 и т. д., каждый раз будут разными числами, выступая в качестве параметров a, b и c. В приведенном примере даже X = Y = Z (> 0 и <= 1) удовлетворяют условиям.
Посмотреть работу можно на github.com/sympy/sympy/pull/22389
@DeyvidDimitrov Хорошо, потрясающе. Может быть, это поможет, если вы отредактируете свой вопрос, чтобы упомянуть об этом. Если я не ошибаюсь, оказывается, что эта проблема относится к рубрике «диофантовых неравенств»; веб-поиск находит некоторые ресурсы, например: mathoverflow.net/questions/69966/…
Я не уверен, как лучше это решить, но с помощью кода, который уже доступен здесь, вы можете сделать следующее:
>>> from symyp import *
>>> from sympy.abc import x,y,z
>>> eqs = [31*x + 2.9*y + 25*z <= 160, 23*y + 1.3*z <= 160, 3.6*x + 0.9*y + 33*z <= 50, 165*x + 110.9*y + 402*z <= 1730]
>>> eqs = [nsimplify(i, rational=True) for i in eqs]
>>> sol = solve_linear_inequalities(eqs,(x,y,z))
Вы получите решение для y, указывающее, что оно находится в Interval(-oo, min(...functions of x and z...))
. Выполнение того же для функций x и z в min
дает решение для z, подобное Interval(-oo, min(...const or functions of x...))
. Наконец, то же самое для функций x в min показывает, что x находится в интервале (-oo, 5.16). Таким образом, для x в диапазоне (1,6) вы можете вычислить соответствующие диапазоны для z, а затем y. Вот просто цикл грубой силы:
>>> yy = sol[y]
for xx in range(6):
for zz in range(6):
yi = yy.subs(x,xx).subs(z,zz).intersection(Range(1,oo))
if not yi:continue
print(xx,yi,zz)
который дает
0 Range(1, 7, 1) 0
0 Range(1, 7, 1) 1
1 Range(1, 7, 1) 0
1 Range(1, 7, 1) 1
2 Range(1, 7, 1) 0
2 Range(1, 7, 1) 1
3 Range(1, 7, 1) 0
3 Range(1, 7, 1) 1
4 Range(1, 7, 1) 0
4 Range(1, 3, 1) 1
5 Range(1, 2, 1) 0
Без целевой функции, которую нужно максимизировать, похоже, что существует конечное число целочисленных решений ваших уравнений. Возможно, этого достаточно, чтобы подтолкнуть вас к более общему решению вашей проблемы? Кроме того, если вы укажете диапазон интересов для x, y и z, это поможет, например. если все они положительные, то дано решение для каждой переменной
>>> sol = solve_linear_inequalities(eqs + [x>0,y>0,z>0], (x, y, z))
>>> for i in sol:
... print(i, sol[i])
z Interval(0, 50/33)
x Interval(0, Min(160/31 - 25*z/31, 346/33 - 134*z/55, 125/9 - 55*z/6))
y Interval(0, Min(160/23 - 13*z/230, -310*x/29 - 250*z/29 + 1600/29, -4*x - 110*z/3 + 500/9, -1650*x/1109 - 4020*z/1109 + 17300/1109))
Поэтому выберите значение из диапазона для z, рассчитайте допустимые диапазоны для x и выберите значение x и, наконец, вычислите допустимый диапазон для y.
Ошибка генерируется
((Poly(31*x + 2.9*y + 25*z), Poly(1)), '<=', Poly(160))
. Дело даже не в том, чтобы назвать решение. Я не работал с этим решателем, но ваши выражения не похожи на его задокументированные примеры.