python Python中的数学方程操作
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1010583/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Mathematical equation manipulation in Python
提问by Leafy
I want to develop a GUI application which displays a given mathematical equation. When you click upon a particular variable in the equation to signify that it is the unknown variable ie., to be calculated, the equation transforms itself to evaluate the required unknown variable.
我想开发一个显示给定数学方程的 GUI 应用程序。当您单击方程中的特定变量以表示它是未知变量,即要计算时,方程会自行转换以评估所需的未知变量。
For example:
例如:
a = (b+c*d)/e
Let us suppose that I click upon "d" to signify that it is the unknown variable. Then the equation should be re-structured to:
让我们假设我点击“d”来表示它是未知变量。那么方程应该重新构造为:
d = (a*e - b)/c
As of now, I just want to know how I can go about rearranging the given equation based on user input. One suggestion I got from my brother was to use pre-fix/post-fix notational representation in back end to evaluate it.
到目前为止,我只想知道如何根据用户输入重新排列给定的方程。我从我兄弟那里得到的一个建议是在后端使用修复前/修复后符号表示来评估它。
Is that the only way to go or is there any simpler suggestion? Also, I will be using not only basic mathematical functions but also trignometric and calculus (basic I think. No partial differential calculus and all that) as well. I think that the pre/post-fix notation evaluation might not be helpful in evaluation higher mathematical functions.
这是唯一的方法还是有更简单的建议?此外,我不仅会使用基本的数学函数,还会使用三角函数和微积分(我认为是基本的。没有偏微分之类的)。我认为修复前/修复后符号评估可能对评估更高的数学函数没有帮助。
But that is just my opinion, so please point out if I am wrong. Also, I will be using SymPyfor mathematical evaluation so evaluation of a given mathematical equation is not a problem, creating a specific equation from a given generic one is my main problem.
但这只是我的意见,所以如果我错了,请指出。此外,我将使用SymPy进行数学评估,因此对给定数学方程的评估不是问题,从给定的通用方程创建特定方程是我的主要问题。
回答by Paul
Using SymPy, your example would go something like this:
使用SymPy,您的示例将如下所示:
>>> 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]
>>>
It seems to work for trigonometric functions too:
它似乎也适用于三角函数:
>>> l = a
>>> r = b*sympy.sin(c)
>>> sympy.solve(l-r,c)
[asin(a/b)]
>>>
And since you are working with a GUI, you'll (probably) want to convert back and forth from strings to expressions:
由于您使用的是 GUI,您(可能)希望在字符串和表达式之间来回转换:
>>> r = '(b+c*d)/e'
>>> sympy.sympify(r)
(b + c*d)/e
>>> sympy.sstr(_)
'(b + c*d)/e'
>>>
or you may prefer to display them as rendered LaTeX or MathML.
或者您可能更喜欢将它们显示为渲染的LaTeX 或 MathML。
回答by Nicolas Dumazet
If you want to do this out of the box, without relying on librairies, I think that the problems you will find are not Python related. If you want to find such equations, you have to describe the heuristics necessary to solve these equations.
如果你想开箱即用,不依赖库,我认为你会发现的问题与 Python 无关。如果你想找到这样的方程,你必须描述求解这些方程所需的启发式方法。
First, you have to represent your equation. What about separating:
首先,您必须表示您的等式。分离怎么样:
- operands:
- symbolic operands (a,b)
- numeric operands (1,2)
- operators:
- unary operators (-, trig functions)
- binary operators (+,-,*,/)
- 操作数:
- 符号操作数 (a,b)
- 数字操作数 (1,2)
- 运营商:
- 一元运算符(-、三角函数)
- 二元运算符(+、-、*、/)
Unary operators will obviously enclose one operand, binary ops will enclose two.
一元运算符显然会包含一个操作数,二元操作会包含两个。
What about types?
类型呢?
I think that all of these components should derivate from a single common expression
type.
And this class would have a getsymbols
method to locate quickly symbols in your expressions.
我认为所有这些组件都应该从一个通用expression
类型派生出来。这个类将有一个getsymbols
方法来快速定位表达式中的符号。
And then distinguish between unary and binary operators, add a few basic complement/reorder primitives...
然后区分一元和二元运算符,添加一些基本的补码/重新排序原语...
Something like:
就像是:
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)
With this basic structure set up, you should be able to describe a simple heuristic to solve very simple equations. Just think of the simple rules you learned to solve equations, and write them down. That should work :)
有了这个基本结构设置,您应该能够描述一个简单的启发式方法来求解非常简单的方程。想想你学到的解方程的简单规则,然后把它们写下来。那应该工作:)
And then a very naive solver:
然后是一个非常幼稚的求解器:
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
回答by Caleb Hattingh
Things have sure changed since 2009. I don't know how your GUI application is going, but this is now possible directly in IPython qtconsole (which one could embed inside a custom PyQt/PySide application, and keep track of all the defined symbols, to allow GUI interaction in a separate listbox, etc.)
自 2009 年以来,情况确实发生了变化。我不知道您的 GUI 应用程序进展如何,但现在可以直接在 IPython qtconsole 中实现(可以将其嵌入自定义 PyQt/PySide 应用程序中,并跟踪所有定义的符号,允许在单独的列表框中进行 GUI 交互等)
(Uses the sympyprt
extension for IPython)
(使用sympyprt
IPython的扩展)
回答by David Johnstone
What you want to do isn't easy. Some equations are quite straight forward to rearrange (like make b
the subject of a = b*c+d
, which is b = (a-d)/c
), while others are not so obvious (like make x
the subject of y = x*x + 4*x + 4
), while others are not possible (especially when you trigonometric functions and other complications).
你想做的事情并不容易。一些方程很容易重新排列(例如使b
主语为a = b*c+d
,即b = (a-d)/c
),而另一些则不那么明显(如使x
主语为y = x*x + 4*x + 4
),而另一些则不可能(尤其是当您使用三角函数和其他复杂情况时)。
As other people have said, check out Sage. It doeswhat you want:
正如其他人所说,请查看 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)]
回答by Dan Lorenc
Sage has support for symbolic math. You could just use some of the equation manipulating functions built-in:
Sage 支持符号数学。您可以只使用一些内置的方程操作函数: