general expression substitution in sympy

dsh*_*hin 5 sympy

I have two univariate functions, f(x) and g(x), and I'd like to substitute g(x) = y to rewrite f(x) as some f2(y).

Here is a simple example that works:

In [240]: x = Symbol('x')

In [241]: y = Symbol('y')

In [242]: f = abs(x)**2 + 6*abs(x) + 5

In [243]: g = abs(x)

In [244]: f.subs({g: y})
Out[244]: y**2 + 6*y + 5
Run Code Online (Sandbox Code Playgroud)

But now, if I try a slightly more complex example, it fails:

In [245]: h = abs(x) + 1

In [246]: f.subs({h: y})
Out[246]: Abs(x)**2 + 6*Abs(x) + 5
Run Code Online (Sandbox Code Playgroud)

Is there a general approach that works for this problem?

小智 5

该表达式abs(x)**2 + 6*abs(x) + 5实际上并不包含abs(x) + 1任何地方,因此没有什么可以替代的。

可以想象将其更改为abs(x)**2 + 5*(abs(x) + 1) + abs(x),替换结果为abs(x)**2 + 5*y + abs(x)。或者也许将其更改为abs(x)**2 + 6*(abs(x) + 1) - 1,结果是abs(x)**2 + 6*y - 1. 还有其他选择。结果应该是什么?

这个任务没有通用的方法,因为它不是一个明确定义的任务。

相比之下,替换f.subs(abs(x), y-1)是一个明确的指令,将表达式树中所有出现的 abs(x) 替换为y-1。它返回6*y + (y - 1)**2 - 1

上面的abs(x) + 1in替换abs(x)**2 + 6*abs(x) + 5也是一个明确的指令:在表达式abs(x) + 1的语法树中找到表达式的确切出现abs(x)**2 + 6*abs(x) + 5,并将这些子树替换为表达式的语法树abs(x) + 1。不过,有一个关于启发式的警告。

旁白:除了subsSymPy之外,还有一个.replace支持通配符的方法,但我不希望它在这里有所帮助。根据我的经验,急于更换:

>>> a = Wild('a')
>>> b = Wild('b')
>>> f.replace(a*(abs(x) + 1) + b, a*y + b)
5*y/(Abs(x) + 1) + 6*y*Abs(x*y)/(Abs(x) + 1)**2 + (Abs(x*y)/(Abs(x) + 1))**(2*y/(Abs(x) + 1))   
Run Code Online (Sandbox Code Playgroud)

消除一个变量

SymPy 中没有“消除”。可以尝试solve通过引入另一个变量来模拟它,例如,

fn = Symbol('fn')
solve([Eq(fn,  f), Eq(abs(x) + 1, y)], [fn, x])
Run Code Online (Sandbox Code Playgroud)

它试图求解“fn”和“x”,因此“fn”的解是一个没有 x 的表达式。如果这有效

事实上,它不适用于abs(); 在 SymPy 中没有实现解决绝对值内的东西。这是一个解决方法。

fn, ax = symbols('fn ax')
solve([Eq(fn,  f.subs(abs(x), ax)), Eq(ax + 1, y)], [fn, ax]) 
Run Code Online (Sandbox Code Playgroud)

这将输出[(y*(y + 4), y - 1)]您想要的第一项;的解决方案fn