问题描述
我有两个单变量函数,f(x)
和 g(x)
,我想用 g(x) = y
将 f(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
支持通配符,但我不希望它在这里有所帮助.根据我的经验,更换过于急切:
消除一个变量
没有消除"在 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 中的一般表达式替换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!