Sympy:如何将乘积对数简化为对数之和?

4
为了帮助理解,sympy.concrete提供了一些高效的工具来处理符号和。如果要将这些工具应用于符号积,则需要取对数。然而,简单地取对数并不能自动给出转换结果:
import sympy as sp
sp.init_printing() # display math as latex
z = sp.Symbol('z')
j,k = sp.symbols('j,k')
Prod = sp.Product( (z + sp.sqrt(1-4*j*z**2))**(-1), (j,1,k) )
sp.log(Prod)

提供

\log{\left (\prod_{j=1}^{k} \frac{1}{z + \sqrt{- 4 j z^{2} + 1}} \right )}

以所有可能的变化方式:

sp.log(Prod)
sp.log(Prod).expand()
sp.log(Prod).simplify()
sp.expand_log(sp.log(Prod),force=True)

问题:如何将其转换为对数的和?

相关:

如何在sympy中简化指数的对数?


这是一个有效的问题,尽管在这种情况下,我会采用手工数学方法,在使用Sympy进行进一步处理之前自己完成这一步骤。当然,如果这是一系列操作的一部分,这不会是一个解决方案。 - Ignacio Vergara Kausel
当然,这只是一个“玩具示例”。我尝试使用CAS来避免在大表达式中手动犯愚蠢的错误,即使这需要更多时间。 - Sergey Dovgal
z是一个复数,或者\sqrt{1-4jz^2}是吗?如果在复平面上使用主分支对数,则乘积的对数不等于对数之和。SymPy正确地避免了这个错误。 - user6655984
是的,我又犯了同样的错误 :) Sympy默认假设有时让我感到有些困惑。例如,如果zj不可交换怎么办?如果z是四元数呢?默认情况下总是假定z是复数,但我怀疑人类默认会假定一个变量是实数,并指定一个标志is_complex = True。好吧,这只是实现的细节,我必须习惯它。谢谢你的提醒。 - Sergey Dovgal
我编辑了问题,以显示使用force选项的expand_log也失败了。 - Sergey Dovgal
等等,如果变量 ab 是复数,那么 log(ab) 作为多元函数是等于 log(a) + log(b) 的,不是吗?;) 好吧,也许不是主分支,但仍然... - Sergey Dovgal
1个回答

6

如果还没有符合需求的标准函数,我写了一个自己的函数,模仿以下行为:

sp.expand_log(expr, force=True)

该代码会递归地检查表达式,试图找到模式为 log(product) 的部分,并将其替换为 sum(log)。此外,该代码还支持多索引求和。
def concrete_expand_log(expr, first_call = True):
    import sympy as sp
    if first_call:
        expr = sp.expand_log(expr, force=True)
    func = expr.func
    args = expr.args
    if args == ():
        return expr
    if func == sp.log:
        if args[0].func == sp.concrete.products.Product:
            Prod = args[0]
            term = Prod.args[0]
            indices = Prod.args[1:]
            return sp.Sum(sp.log(term), *indices)
    return func(*map(lambda x:concrete_expand_log(x, False), args))

Example.

import sympy as sp
from IPython.display import display
sp.init_printing() # display math as latex
z = sp.Symbol('z')
j,k,n = sp.symbols('j,k,n')
Prod = sp.Product( (z + sp.sqrt(1-4*j*z**2))**(-1), (j,0,k))
expr = sp.log(z**(n-k) * (1 - sp.sqrt((1 - 4*(k+2)*z**2)/(1-4*(k+1)*z**2)) ) * Prod)
display(expr)

\log{\left (z^{- k + n} \left(- \sqrt{\frac{- z^{2} \left(4 k + 8\right) + 1}{- z^{2} \left(4 k + 4\right) + 1}} + 1\right) \prod_{j=0}^{k} \frac{1}{z + \sqrt{- 4 j z^{2} + 1}} \right )}

display(concrete_expand_log(expr))

\left(- k + n\right) \log{\left (z \right )} + \log{\left (- \sqrt{\frac{- z^{2} \left(4 k + 8\right) + 1}{- z^{2} \left(4 k + 4\right) + 1}} + 1 \right )} + \sum_{j=0}^{k} \log{\left (\frac{1}{z + \sqrt{- 4 j z^{2} + 1}} \right )}


x,y = sympy.symbols('x y', positive=True);sympy.expand_log(sympy.log(x*y)) 给出了 log(x) + log(y)。在相关问题中建议使用 positive=True,这似乎有所不同。我不知道这是否已经添加到 sympy 中。 - 2bigpigs
1
我的问题是如何将其应用于符号Sympy乘积,而不仅仅是两个项的乘积。我没有办法通过传递某种标志来强制整个表达式为正。虽然这对于两个Sympy变量有效。 - Sergey Dovgal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接