Reputation: 2073
I have expressions containing a relational operator, symbols, and constants. I'd like to rearrange the expressions so that (to the extent possible) all the constant terms are on one side of the relational operator, and the remaining terms on the other side. For example, I'd like to rearrange:
x - 5 > y - z
to:
x - y + z > 5
Is there an existing sympy method for doing this? If not, where should I start in extending sympy?
Upvotes: 4
Views: 1148
Reputation: 19029
The omission of this from the canonical
method was probably an oversight.
Perhaps the following would work for your else
clause
r, l = (ineq.lhs - ineq.rhs).as_coeff_Add()
if r < 0:
l, r = -r, -l
return Relational(l, r, ineq.rel_op).canonical
One might imagine that canonical would remove common factors, too, so 2x<4y
would become x<2*y
. SymPy would be open to a pull request implementing such changes.
Upvotes: 0
Reputation: 20344
Somewhat surprisingly, I couldn't find a way to do this "out of the box". You can use the method in this question to make any one variable the sole subject of the left hand side (LHS) of the inequality but I can't seem to make the constant term the subject.
So, I wrote my own version and reproduce it below. I've tested it on the example given and a couple of other examples. It tries to make the right hand side (RHS) consist of either zero or only constant terms based on an optional parameter. There may well be corner cases where it fails - use / modify with caution.
import sympy
from sympy.core.relational import Relational
mult_by_minus_one_map = {
None: '==',
'==': '==',
'eq': '==',
'!=': '!=',
'<>': '!=',
'ne': '!=',
'>=': '<=',
'ge': '<=',
'<=': '>=',
'le': '>=',
'>': '<',
'gt': '<',
'<': '>',
'lt': '>',
}
def move_inequality_constants(ineq, zero_on_right=False):
l = ineq.lhs
r = ineq.rhs
op = ineq.rel_op
all_on_left = l - r
if zero_on_right:
return Relational(all_on_left, sympy.sympify(0), op)
else:
coeff_dict = all_on_left.as_coefficients_dict()
var_types = coeff_dict.keys()
new_rhs = sympy.sympify(0)
for s in var_types:
if s == 1:
all_on_left = all_on_left - coeff_dict[s]
new_rhs = new_rhs - coeff_dict[s]
if new_rhs < 0:
all_on_left = all_on_left * -1
new_rhs = new_rhs * -1
op = mult_by_minus_one_map[op]
return Relational(all_on_left,new_rhs,op)
# test code to demo function below
from sympy.abc import x,y,z
test_ineqs = [ x - 5 > y - z,
x**2 + x - 5 > y + x**2 - z,
x + 5 > y - z,
x**3 + y**2 >= x + 5*y - z - 15]
for k in test_ineqs:
print('Re-arranging '+ str(k))
kn = move_inequality_constants(k)
print('Gives '+str(kn))
print('Or equivalently ' + str(move_inequality_constants(k, True)))
print('====')
Re-arranging x - 5 > y - z
Gives x - y + z > 5
Or equivalently x - y + z - 5 > 0
====
Re-arranging x**2 + x - 5 > x**2 + y - z
Gives x - y + z > 5
Or equivalently x - y + z - 5 > 0
====
Re-arranging x + 5 > y - z
Gives -x + y - z < 5
Or equivalently x - y + z + 5 > 0
====
Re-arranging x**3 + y**2 >= x + 5*y - z - 15
Gives -x**3 + x - y**2 + 5*y - z <= 15
Or equivalently x**3 - x + y**2 - 5*y + z + 15 >= 0
Upvotes: 1