With Sympy, it is possible to define symbolic linear inequalities, like:
This system is equivalent to:
And then it can be represented by a matrix A
of coefficients and a vector b
of upper bounds:
A = np.array([
[-1, 0, 0], # -x
[ 1, 0, 0], # x
[ 0,-1, 0], # -y
[ 1, 1, 0], # x+y
[ 0, 0,-1], # -z
[ 1, 1, 1] # x+y+z
])
b = np.array([5, 4, 5, 3, 10, 6])
I'm wondering whether it is possible to directly get A
and b
from the symbolic linear inequalities, without manual gymnastics?
As far as I know, SymPy doesn't have a function that does what you want. But we can code one. A very basic attempt is the following, which has a lot of assumptions for it to work properly.
from sympy import *
import numpy as np
var("x:z")
i1 = (x >= -5) & (x <= 4)
i2 = (y >= -5) & (y <= 3 - x)
i3 = (z >= -10) & (z <= 6 - 2*x - y)
# relational types: StrictGreaterThan, StrictLessThan, GreaterThan, LessThan
def func(inequalities, symbols, required_type):
# assumptions:
# 1. all inequalities are written with the same relational: < or <= or > or >=
# 2. For each inequality, LHS and RHS are linear in `symbols`
def get_ineq_with_correct_type(i, required_type):
if type(i) != required_type:
i = i.reversed
return i
# extract all inequalities, process them so they are all of the same type and
# terms containing `symbols` are on the LHS.
ineq = []
for i in inequalities:
if isinstance(i, And):
ineq.extend([get_ineq_with_correct_type(a, required_type) for a in i.args])
else:
ineq.append(get_ineq_with_correct_type(i, required_type))
# at this point, all inequalities should be of the same type.
# rewrite them as expressions: LHS - RHS
equations = [i.lhs - i.rhs for i in ineq]
return linear_eq_to_matrix(equations, symbols)
# rewrite all inequalities as LessThan and extract A, b
A, b = func([i1, i2, i3], [x, y, z], LessThan)
print("SymPy A:", A)
print("SymPy b:", b)
A = np.array(A, dtype=float)
b = np.array(b, dtype=float)
print("Numpy A:\n", A)
print("Numpy b:\n", b)
# SymPy A: Matrix([[-1, 0, 0], [1, 0, 0], [0, -1, 0], [1, 1, 0], [0, 0, -1], [2, 1, 1]])
# SymPy b: Matrix([[5], [4], [5], [3], [10], [6]])
# Numpy A:
# [[-1. 0. 0.]
# [ 1. 0. 0.]
# [ 0. -1. 0.]
# [ 1. 1. 0.]
# [ 0. 0. -1.]
# [ 2. 1. 1.]]
# Numpy b:
# [[ 5.]
# [ 4.]
# [ 5.]
# [ 3.]
# [10.]
# [ 6.]]
Note that this has only been tested on your example, where I only changed one coefficient in the last inequality just for fun.