如何重新排列包含关系运算符的 sympy 表达式
How to rearrange sympy expressions containing a relational operator
我有包含关系运算符、符号和常量的表达式。我想重新排列表达式,以便(在可能的范围内)所有常数项都在关系运算符的一侧,而其余项在另一侧。例如,我想重新排列:
x - 5 > y - z
至:
x - y + z > 5
是否有现成的 sympy 方法可以做到这一点?如果没有,我应该从哪里开始扩展 sympy?
有点令人惊讶的是,我找不到执行此操作的方法"out of the box"。您可以使用 中的方法使任何一个变量成为不等式左侧 (LHS) 的唯一主题,但我似乎无法使常数项成为主题。
因此,我编写了自己的版本并在下面重现。我已经在给定的示例和其他几个示例中对其进行了测试。它试图根据可选参数使右侧 (RHS) 由零或仅包含常数项组成。很可能存在失败的极端情况 - 请谨慎使用/修改。
代码:
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
canonical
方法中遗漏了这一点可能是一个疏忽。
也许以下内容适用于您的 else
子句
r, l = (ineq.lhs - ineq.rhs).as_coeff_Add()
if r < 0:
l, r = -r, -l
return Relational(l, r, ineq.rel_op).canonical
人们可能会想象 canonical 也会删除公因子,所以 2x<4y
会变成 x<2*y
。 SymPy 将对实现此类更改的拉取请求开放。
我有包含关系运算符、符号和常量的表达式。我想重新排列表达式,以便(在可能的范围内)所有常数项都在关系运算符的一侧,而其余项在另一侧。例如,我想重新排列:
x - 5 > y - z
至:
x - y + z > 5
是否有现成的 sympy 方法可以做到这一点?如果没有,我应该从哪里开始扩展 sympy?
有点令人惊讶的是,我找不到执行此操作的方法"out of the box"。您可以使用
因此,我编写了自己的版本并在下面重现。我已经在给定的示例和其他几个示例中对其进行了测试。它试图根据可选参数使右侧 (RHS) 由零或仅包含常数项组成。很可能存在失败的极端情况 - 请谨慎使用/修改。
代码:
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
canonical
方法中遗漏了这一点可能是一个疏忽。
也许以下内容适用于您的 else
子句
r, l = (ineq.lhs - ineq.rhs).as_coeff_Add()
if r < 0:
l, r = -r, -l
return Relational(l, r, ineq.rel_op).canonical
人们可能会想象 canonical 也会删除公因子,所以 2x<4y
会变成 x<2*y
。 SymPy 将对实现此类更改的拉取请求开放。