Python中的数学方程处理
我想开发一个GUI应用程序,显示给定的数学公式。当您点击方程中的某个特定变量表示该变量为待计算的未知变量时,方程会自行转换以计算所需的未知变量 例如:Python中的数学方程处理,python,math,equation,Python,Math,Equation,我想开发一个GUI应用程序,显示给定的数学公式。当您点击方程中的某个特定变量表示该变量为待计算的未知变量时,方程会自行转换以计算所需的未知变量 例如: 让我们假设我点击“d”表示它是未知变量。然后,应将方程式重新构造为: 现在,我只想知道如何根据用户输入重新排列给定的等式。我从我哥哥那里得到的一个建议是在后端使用前置/后置的符号表示来评估它 这是唯一的办法还是有更简单的建议? 此外,我将不仅使用基本的数学函数,而且还将使用三轴测函数和微积分(我认为是基本的,没有偏微分等)。我认为在计算更高的
让我们假设我点击“d”表示它是未知变量。然后,应将方程式重新构造为:
现在,我只想知道如何根据用户输入重新排列给定的等式。我从我哥哥那里得到的一个建议是在后端使用前置/后置的符号表示来评估它 这是唯一的办法还是有更简单的建议? 此外,我将不仅使用基本的数学函数,而且还将使用三轴测函数和微积分(我认为是基本的,没有偏微分等)。我认为在计算更高的数学函数时,前/后固定符号的计算可能没有帮助 但这只是我的观点,所以如果我错了,请指出。
此外,我还将用于数学评估,因此评估给定的数学方程式不是问题,从给定的通用方程式创建特定方程式是我的主要问题。Sage支持符号数学。您可以只使用一些内置的方程式操作函数:
你想做的事并不容易。有些方程是非常直接地重新排列的(比如make
b
a=b*c+d的主题,即b=(a-d)/c
),而另一些则不那么明显(比如makex
y=x*x+4*x+4),而其他的则不可能(特别是当您使用三角函数和其他复杂函数时)
正如其他人所说,看看Sage。它是你想要的:
You can solve equations for one variable in terms of others:
sage: x, b, c = var('x b c')
sage: solve([x^2 + b*x + c == 0],x)
[x == -1/2*b - 1/2*sqrt(b^2 - 4*c), x == -1/2*b + 1/2*sqrt(b^2 - 4*c)]
使用,您的示例将如下所示:
>>> import sympy
>>> a,b,c,d,e = sympy.symbols('abcde')
>>> r = (b+c*d)/e
>>> l = a
>>> r = sympy.solve(l-r,d)
>>> l = d
>>> r
[(-b + a*e)/c]
>>>
它似乎也适用于三角函数:
>>> l = a
>>> r = b*sympy.sin(c)
>>> sympy.solve(l-r,c)
[asin(a/b)]
>>>
由于您使用的是GUI,您(可能)需要来回地将字符串转换为表达式:
>>> r = '(b+c*d)/e'
>>> sympy.sympify(r)
(b + c*d)/e
>>> sympy.sstr(_)
'(b + c*d)/e'
>>>
或者,您可能更愿意将它们显示为渲染状态。如果您想在不依赖Libraries的情况下,开箱即用,我认为您将发现的问题与Python无关。如果您想找到此类方程,您必须描述解这些方程所需的启发式方法 首先,你必须表示你的方程。分离呢
- 操作数:
- 符号操作数(a,b)
- 数字操作数(1,2)
- 操作员:
- 一元运算符(-,触发函数)
- 二元运算符(+、-、*、/)
表达式
类型。
这个类将有一个getsymbols
方法来快速定位表达式中的符号
然后区分一元运算符和二元运算符,添加一些基本的补码/重排序原语
比如:
class expression(object):
def symbols(self):
if not hasattr(self, '_symbols'):
self._symbols = self._getsymbols()
return self._symbols
def _getsymbols(self):
"""
return type: list of strings
"""
raise NotImplementedError
class operand(expression): pass
class symbolicoperand(operand):
def __init__(self, name):
self.name = name
def _getsymbols(self):
return [self.name]
def __str__(self):
return self.name
class numericoperand(operand):
def __init__(self, value):
self.value = value
def _getsymbols(self):
return []
def __str__(self):
return str(self.value)
class operator(expression): pass
class binaryoperator(operator):
def __init__(self, lop, rop):
"""
@type lop, rop: expression
"""
self.lop = lop
self.rop = rop
def _getsymbols(self):
return self.lop._getsymbols() + self.rop._getsymbols()
@staticmethod
def complementop():
"""
Return complement operator:
op.complementop()(op(a,b), b) = a
"""
raise NotImplementedError
def reorder():
"""
for op1(a,b) return op2(f(b),g(a)) such as op1(a,b) = op2(f(a),g(b))
"""
raise NotImplementedError
def _getstr(self):
"""
string representing the operator alone
"""
raise NotImplementedError
def __str__(self):
lop = str(self.lop)
if isinstance(self.lop, operator):
lop = '(%s)' % lop
rop = str(self.rop)
if isinstance(self.rop, operator):
rop = '(%s)' % rop
return '%s%s%s' % (lop, self._getstr(), rop)
class symetricoperator(binaryoperator):
def reorder(self):
return self.__class__(self.rop, self.lop)
class asymetricoperator(binaryoperator):
@staticmethod
def _invert(operand):
"""
div._invert(a) -> 1/a
sub._invert(a) -> -a
"""
raise NotImplementedError
def reorder(self):
return self.complementop()(self._invert(self.rop), self.lop)
class div(asymetricoperator):
@staticmethod
def _invert(operand):
if isinstance(operand, div):
return div(self.rop, self.lop)
else:
return div(numericoperand(1), operand)
@staticmethod
def complementop():
return mul
def _getstr(self):
return '/'
class mul(symetricoperator):
@staticmethod
def complementop():
return div
def _getstr(self):
return '*'
class add(symetricoperator):
@staticmethod
def complementop():
return sub
def _getstr(self):
return '+'
class sub(asymetricoperator):
@staticmethod
def _invert(operand):
if isinstance(operand, min):
return operand.op
else:
return min(operand)
@staticmethod
def complementop():
return add
def _getstr(self):
return '-'
class unaryoperator(operator):
def __init__(self, op):
"""
@type op: expression
"""
self.op = op
@staticmethod
def complement(expression):
raise NotImplementedError
def _getsymbols(self):
return self.op._getsymbols()
class min(unaryoperator):
@staticmethod
def complement(expression):
if isinstance(expression, min):
return expression.op
else:
return min(expression)
def __str__(self):
return '-' + str(self.op)
建立了这个基本结构后,你应该能够描述一个简单的启发式方法来解决非常简单的方程。只要想想你学会的解决方程的简单规则,并把它们写下来。这应该是可行的:)
然后是一个非常天真的解决者:
def solve(left, right, symbol):
"""
@type left, right: expression
@type symbol: string
"""
if symbol not in left.symbols():
if symbol not in right.symbols():
raise ValueError('%s not in expressions' % symbol)
left, right = right, left
solved = False
while not solved:
if isinstance(left, operator):
if isinstance(left, unaryoperator):
complementor = left.complement
right = complementor(right)
left = complementor(left)
elif isinstance(left, binaryoperator):
if symbol in left.rop.symbols():
left = left.reorder()
else:
right = left.complementop()(right, left.rop)
left = left.lop
elif isinstance(left, operand):
assert isinstance(left, symbolicoperand)
assert symbol==left.name
solved = True
print symbol,'=',right
a,b,c,d,e = map(symbolicoperand, 'abcde')
solve(a, div(add(b,mul(c,d)),e), 'd') # d = ((a*e)-b)/c
solve(numericoperand(1), min(min(a)), 'a') # a = 1
自2009年以来,情况确实发生了变化。我不知道您的GUI应用程序进展如何,但现在可以直接在IPython qtconsole中实现这一点(该控制台可以嵌入到自定义PyQt/PySide应用程序中,并跟踪所有定义的符号,以允许在单独的列表框中进行GUI交互,等等)
(使用IPython的
sympyprt
扩展名)+1从SymPy本身给出可能有用的例子,而不是立即提出Sage(顺便说一句,Sage包括SymPy)。我认为第一段的第二行应该是a,b,c,d,e=SymPy.symbols('abcde')
.IMHO这里最好指向SymPy,而不是SAGE,SAGE是一个庞大的软件包集合,甚至不在Windows上运行(除了在虚拟机中,但这不算在内)。
class expression(object):
def symbols(self):
if not hasattr(self, '_symbols'):
self._symbols = self._getsymbols()
return self._symbols
def _getsymbols(self):
"""
return type: list of strings
"""
raise NotImplementedError
class operand(expression): pass
class symbolicoperand(operand):
def __init__(self, name):
self.name = name
def _getsymbols(self):
return [self.name]
def __str__(self):
return self.name
class numericoperand(operand):
def __init__(self, value):
self.value = value
def _getsymbols(self):
return []
def __str__(self):
return str(self.value)
class operator(expression): pass
class binaryoperator(operator):
def __init__(self, lop, rop):
"""
@type lop, rop: expression
"""
self.lop = lop
self.rop = rop
def _getsymbols(self):
return self.lop._getsymbols() + self.rop._getsymbols()
@staticmethod
def complementop():
"""
Return complement operator:
op.complementop()(op(a,b), b) = a
"""
raise NotImplementedError
def reorder():
"""
for op1(a,b) return op2(f(b),g(a)) such as op1(a,b) = op2(f(a),g(b))
"""
raise NotImplementedError
def _getstr(self):
"""
string representing the operator alone
"""
raise NotImplementedError
def __str__(self):
lop = str(self.lop)
if isinstance(self.lop, operator):
lop = '(%s)' % lop
rop = str(self.rop)
if isinstance(self.rop, operator):
rop = '(%s)' % rop
return '%s%s%s' % (lop, self._getstr(), rop)
class symetricoperator(binaryoperator):
def reorder(self):
return self.__class__(self.rop, self.lop)
class asymetricoperator(binaryoperator):
@staticmethod
def _invert(operand):
"""
div._invert(a) -> 1/a
sub._invert(a) -> -a
"""
raise NotImplementedError
def reorder(self):
return self.complementop()(self._invert(self.rop), self.lop)
class div(asymetricoperator):
@staticmethod
def _invert(operand):
if isinstance(operand, div):
return div(self.rop, self.lop)
else:
return div(numericoperand(1), operand)
@staticmethod
def complementop():
return mul
def _getstr(self):
return '/'
class mul(symetricoperator):
@staticmethod
def complementop():
return div
def _getstr(self):
return '*'
class add(symetricoperator):
@staticmethod
def complementop():
return sub
def _getstr(self):
return '+'
class sub(asymetricoperator):
@staticmethod
def _invert(operand):
if isinstance(operand, min):
return operand.op
else:
return min(operand)
@staticmethod
def complementop():
return add
def _getstr(self):
return '-'
class unaryoperator(operator):
def __init__(self, op):
"""
@type op: expression
"""
self.op = op
@staticmethod
def complement(expression):
raise NotImplementedError
def _getsymbols(self):
return self.op._getsymbols()
class min(unaryoperator):
@staticmethod
def complement(expression):
if isinstance(expression, min):
return expression.op
else:
return min(expression)
def __str__(self):
return '-' + str(self.op)
def solve(left, right, symbol):
"""
@type left, right: expression
@type symbol: string
"""
if symbol not in left.symbols():
if symbol not in right.symbols():
raise ValueError('%s not in expressions' % symbol)
left, right = right, left
solved = False
while not solved:
if isinstance(left, operator):
if isinstance(left, unaryoperator):
complementor = left.complement
right = complementor(right)
left = complementor(left)
elif isinstance(left, binaryoperator):
if symbol in left.rop.symbols():
left = left.reorder()
else:
right = left.complementop()(right, left.rop)
left = left.lop
elif isinstance(left, operand):
assert isinstance(left, symbolicoperand)
assert symbol==left.name
solved = True
print symbol,'=',right
a,b,c,d,e = map(symbolicoperand, 'abcde')
solve(a, div(add(b,mul(c,d)),e), 'd') # d = ((a*e)-b)/c
solve(numericoperand(1), min(min(a)), 'a') # a = 1