本文介绍了sympy 中的一般表达式替换的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个单变量函数,f(x)g(x),我想用 g(x) = yf(x) 重写为某些 f2(y).

这是一个简单的例子:

In [240]: x = Symbol('x')在 [241] 中:y = Symbol('y')在 [242] 中:f = abs(x)**2 + 6*abs(x) + 5在 [243] 中:g = abs(x)在 [244]: f.subs({g: y})输出[244]:y**2 + 6*y + 5

但是现在,如果我尝试一个稍微复杂一点的例子,它就会失败:

在[245]中:h = abs(x) + 1在 [246]: f.subs({h: y})输出[246]:绝对(x)**2 + 6*绝对(x) + 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) 是一个明确的指令,用 y 替换表达式树中所有出现的 abs(x)-1.它返回 6*y + (y - 1)**2 - 1.

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

旁白:除了 subs SymPy 还有一个方法 .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/(绝对值(x) + 1))

消除一个变量

没有消除"在 SymPy 中.可以通过引入另一个变量来尝试使用 solve 来模拟它,例如,

fn = Symbol('fn')解决([Eq(fn, f), Eq(abs(x) + 1, y)], [fn, x])

试图求解fn";和x",因此是fn"的解.是一个没有 x 的表达式.如果可行

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

fn, ax = symbols('fn ax')解决([Eq(fn, f.subs(abs(x), ax)), Eq(ax + 1, y)], [fn, ax])

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

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

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

Is there a general approach that works for this problem?

解决方案

The expression abs(x)**2 + 6*abs(x) + 5 does not actually contain abs(x) + 1 anywhere, so there is nothing to substitute for.

One can imagine changing it to abs(x)**2 + 5*(abs(x) + 1) + abs(x), with the substitution result being abs(x)**2 + 5*y + abs(x). Or maybe changing it to abs(x)**2 + 6*(abs(x) + 1) - 1, with the result being abs(x)**2 + 6*y - 1. There are other choices too. What should the result be?

There is no general approach to this task because it's not a well-defined task to begin with.

In contrast, the substitution f.subs(abs(x), y-1) is a clear instruction to replace all occurrences of abs(x) in the expression tree with y-1. It returns 6*y + (y - 1)**2 - 1.

The substitution above of abs(x) + 1 in abs(x)**2 + 6*abs(x) + 5 is a clear instruction too: to find exact occurrences of the expression abs(x) + 1 in the syntax tree of the expression abs(x)**2 + 6*abs(x) + 5, and replace those subtrees with the syntax tree of the expression abs(x) + 1. There is a caveat about heuristics though.

Aside: in addition to subs SymPy has a method .replace which supports wildcards, but I don't expect it to help here. In my experience, it is overeager to 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))

Eliminate a variable

There is no "eliminate" in SymPy. One can attempt to emulate it with solve by introducing another variable, e.g.,

fn = Symbol('fn')
solve([Eq(fn,  f), Eq(abs(x) + 1, y)], [fn, x])

which attempts to solve for "fn" and "x", and therefore the solution for "fn" is an expression without x. If this works

In fact, it does not work with abs(); solving for something that sits inside an absolute value is not implemented in SymPy. Here is a workaround.

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

This outputs [(y*(y + 4), y - 1)] where the first term is what you want; a solution for fn.

这篇关于sympy 中的一般表达式替换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-28 20:04