2009-06-18 39 views
11

与えられた数式を表示するGUIアプリケーションを開発したいと思います。方程式中の特定の変数をクリックして、それが未知の変数、すなわち計算されることを示すと、方程式は必要な未知の変数を評価するために変換されます。例えばPythonでの数式操作


a = (b+c*d)/e 

私たちは、私はそれが不明な変数であることを意味する "D" 時にクリックしたとしましょう。

d = (a*e - b)/c 

は、今のところ、私はちょうど私がユーザーの入力に基づいて、指定された式を再配置については行くことができる方法を知りたい:次に式はに再構成されるべきです。私が弟から得た1つの提案は、バックエンドでプレフィックス/ポストフィックスの表記表現を使用して評価することでした。

これが唯一の方法ですか、それとももっと簡単な提案ですか? また、私は基本的な数学関数だけでなく、三角法や微積分(基本的には思うが、部分微分計算はありません)も使用します。修正前/修正後の表記の評価は、より高い数学的関数の評価には役立ちません。

しかし、これは私の意見ですので、間違っていると指摘してください。 また、SymPyを数学的評価に使用するので、与えられた数式の評価は問題ではなく、特定の一般式から特定の方程式を作成することが私の主な問題です。

答えて

3

賢者は象徴的な数学をサポートしています。あなただけのビルトイン式操作機能の一部を使用することができます:

http://sagemath.org/

+0

IMHO Windows上で実行されていないパッケージの大規模な集約であるSAGEの代わりに、ここでSymPyを指し示すほうがはるかに優れています(ただし、仮想マシンは例外ですが、これは数えません)。 –

4

何がやりたいことは容易ではありません。 (ba = b*c+dの件名、b = (a-d)/cのように)並べ替えるのは簡単な方程式ですが、それ以外はあまり明白ではありません(y = x*x + 4*x + 4の件名のように)。他の方法は不可能ですが(特に三角関数と他の合併症)。

他の人が言ったように、セージをチェックしてください。また、あなたが望むものdoes

SymPyを使用して
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)] 
21

、あなたの例では、このような何か行くだろう:

>>> 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' 
>>> 

またはレンダリングされたものをLaTeX or MathMLとして表示したい場合があります。

+1

+1(おそらく、SymPyを含む)Sageをすぐに起動するのではなく、おそらく参考になるSymPyの例を与えるためです。 –

6

librairiesに頼らずにこれをそのまま実行したい場合は、Pythonに関連する問題ではないと思います。このような方程式を見つけたい場合は、これらの方程式を解くために必要な経験則を記述する必要があります。

まず、方程式を表す必要があります。どのような分離について:

  • オペランド:
    • シンボリックオペランド(a、b)は
    • 数値オペランド(1,2)
  • 演算子:
    • 単項演算子( - 、trig関数)
    • バイナリ演算子(+、 - 、*、/)

単項演算子は明らかに1つのオペランドを同封します、バイナリOPSは2を同封します。

どのような種類ですか?

私は、これらのコンポーネントのすべてが単一の共通のexpressionタイプから派生する必要があると思います。 そして、このクラスには式内のシンボルをすばやく見つける方法があります(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 
5

物事は必ず私はあなたのGUIアプリケーションが起こっているかわからないが、これはIPythonで直接可能になりました2009年以降に変更されました(等一つはカスタムPyQtは/ PySideアプリケーション内に埋め込む、独立リストボックスにGUIとの対話を可能にするために、すべての定義されたシンボルを追跡することができ、)qtconsoleは

enter image description here

(使用します拡張子がIPython