PythonのSympyモジュールのx**2
乗法形式(つまり)になど、代数の累乗を拡張する既存の方法があるかどうか疑問に思っていますか?x**2 -> x*x
ありがとう!
これを直接サポートすることはできません。SymPyは、べき乗から指数への乗算で一般的な用語を自動的に結合します。これを起こさないための唯一の方法は、evaluate=False
メカニズムを使用することです。例えば
>>> Mul(x, x, evaluate=False)
x*x
この正確な質問について、しばらく前にSymPyメーリングリストで議論がありました(https://groups.google.com/d/topic/sympy/qaJGesRbX_0/discussion)。これを行うコードをそこに投稿しました。ここで繰り返します:
def pow_to_mul(expr):
"""
Convert integer powers in an expression to Muls, like a**2 => a*a.
"""
pows = list(expr.atoms(Pow))
if any(not e.is_Integer for b, e in (i.as_base_exp() for i in pows)):
raise ValueError("A power contains a non-integer exponent")
repl = zip(pows, (Mul(*[b]*e,evaluate=False) for b,e in (i.as_base_exp() for i in pows)))
return expr.subs(repl)
仕組みは次のとおりです
>>> a = Symbol('a')
>>> exp = a**2
>>> print(exp)
a**2
>>> print(pow_to_mul(exp))
a*a
ここでは、メーリングリストと同じ注意事項を示します。「evaluate = Falseはややハックなので、壊れやすいことに注意してください。一部の関数は式を再評価してPowに戻します。他の関数は壊れます。いくつかの予想される不変条件は、evaluate = False式によって壊されます(たとえば、factor()が正しく機能するとは思えません)。」
そのようなことはないようです、それは逆だけをします。
sympyは常に最も簡単な方法で出力を表示するので、常に次のように表示されます。
(x**2).expand() -> x**2
simplify(x**2) -> x**2
replaceメソッドは、このタスクの単純な式に適しています。
>>> expr = (x**2 + 1)/(x**3 - 2*x)
>>> expr.replace(
... lambda x: x.is_Pow and x.exp > 0,
... lambda x: Mul(*[x.base]*x.exp, evaluate=False))
(x*x + 1)/(-2*x + x*x*x)
1/x**3
またはのようなものを処理するには、微調整が必要になりますx**2*(1 + x**2)
。ただし、式の分子と分母を展開して別々に処理すると、必要な処理が実行される場合があります。そして、ベースが常にシンボルである場合、このシンボルハッカーはトリックをさらにうまく行う可能性があります:
>>> def sack(expr):
... return expr.replace(
... lambda x: x.is_Pow and x.exp > 0,
... lambda x: Symbol('*'.join([x.base.name]*x.exp)))
...
>>> sack(-x**2)
-x*x
>>> sack(x**2*(1 + x**3)
x*x*(x*x*x + 1)
アーロンの受け入れられた答えとそれに対する私のコメントに続いて、これは、部分式が評価されるのを避けるために(したがって、乗算のチェーンへのパワーの拡張を失う)xreplace
、最終行の代わりに使用しているバージョンです。subs
def non_eval_xreplace(expr, rule):
"""
Duplicate of sympy's xreplace but with non-evaluate statement included
"""
if expr in rule:
return rule[expr]
elif rule:
args = []
altered = False
for a in expr.args:
try:
new_a = non_eval_xreplace(a, rule)
except AttributeError:
new_a = a
if new_a != a:
altered = True
args.append(new_a)
args = tuple(args)
if altered:
return expr.func(*args, evaluate=False)
return expr
この機能は、呼び出しに渡されるxreplace
ようにすることで、SymPyライブラリの既存の機能に追加できると考えていました。これはあなたがやりたいことですか、それとも大多数のユーザーにとって不必要に複雑ですか?(または、上記のコメントを誤解しましたか?これを行うためのより簡単な方法はありますか?)**kwargs
expr.func
他の回答は処理されない-x**2
ので、代わりに正規表現を使用して2の累乗のみを解決しました。これは少しハッキーだと理解していますが、うまくいきました。
from sympy.printing import ccode
import re
CPOW = re.compile(r'pow\((?P<var>[A-Za-z_]\w*)\s*,\s*2\s*\)')
def to_c_code(expr):
code = ccode(expr)
# sympy has a hard time unsimplifying x**2 to x*x
# replace all pow(var,2) with var*var
code = re.sub(CPOW, r'\g<var>*\g<var>', code)
return code