【问题标题】:Sympy - Simplify expression within domainSympy - 简化域内的表达式
【发布时间】:2020-07-13 18:57:11
【问题描述】:

Sympy 能否自动简化包含以下术语的表达式:

cos(x)/(cos(x)**2)**(1/2)

在我感兴趣的0 <= x <= pi/2的域中可以简化为1

(可以在该域中简化的其他术语示例:acos(cos(x)); sqrt(sin(x)**2); sqrt(cos(2*x) + 1); 等等)

【问题讨论】:

    标签: sympy simplify


    【解决方案1】:

    如果你知道你的表达式中有哪些函数(如sincostan),你可以根据这个stack overflow question做如下操作:

    from sympy import *
    
    x = symbols("x", positive=True)
    ex = cos(x)/(cos(x)**2)**(S(1)/2)
    ex = refine(ex, Q.positive(sin(x)))
    ex = refine(ex, Q.positive(cos(x)))
    ex = refine(ex, Q.positive(tan(x)))
    print(ex)
    

    请注意,Q.positive(x*(pi/2-x)) 在简化三角函数的过程中没有帮助,尽管这正是您通常想要的。

    但是,如果您可能拥有像 polygamma 这样的疯狂函数怎么办?根据我的理解,以下适用于ex 的一些任意选择。

    如果之前SymPy已经生成了表达式,那也没有问题,但是如果你手动输入表达式,我建议使用S(1)/2Rational(1, 2)来描述一半。

    from sympy import *
    
    # define everything as it would have come from previous code
    # also define another variable y to be positive
    x, y = symbols("x y", positive=True)
    ex = cos(x)/(cos(x)**2)**(S(1)/2)
    
    # If you can, always try to use S(1) or Rational(1, 2)
    # if you are defining fractions.
    # If it's already a pre-calculated variable in sympy, 
    # it will already understand it as a half, and you 
    # wouldn't have any problems.
    # ex = cos(x)/(cos(x)**2)**(S(1)/2)
    
    # if x = arctan(y) and both are positive,
    # then we have implicitly that 0 < x < pi/2
    ex = simplify(ex.replace(x, atan(y)))
    # revert back to old variable x if x is still present
    ex = simplify(ex.replace(y, tan(x)))
    print(ex)
    

    这个技巧也可以用来定义其他范围。例如,如果你想要1 &lt; x,那么你可以有x = exp(y) where y = Symbol("y", positive=True)

    我认为 subs() 也可以代替 replace() 工作,但我只是喜欢强制替换,因为 SymPy 有时会忽略 subs() 命令来处理某些变量类型,例如列表和其他东西。

    【讨论】:

    • 如果我输入例如不起作用“ex = Abs(sin(x))”,应该简化为 sin(x)。相反,我得到“tan(x)*Abs(cos(x))”,这可能不太简单。
    • @BernardoCosta 如果您特别知道您只需要处理预先选择的功能,我更新了处理这些事情的答案。我不认为 SymPy 目前能做得比这更好。
    • 这对我现在认为已解决的问题有很大帮助。非常感谢!
    • 然而,类似“ex = Abs(sin(x) + cos(x))”的东西仍然不能简化为“sin(x) + cos(x)”。所以我想仍然需要大量的手工工作才能涵盖所有情况。
    【解决方案2】:

    您可以替换具有您想要的假设的符号:

    In [27]: e = cos(x)/(cos(x)**2)**(S(1)/2) + cos(x)                                                                     
    
    In [28]: e                                                                                                             
    Out[28]: 
                cos(x)   
    cos(x) + ────────────
                _________
               ╱    2    
             ╲╱  cos (x) 
    
    In [29]: cosx = Dummy('cosx', positive=True)                                                                           
    
    In [30]: e.subs(cos(x), cosx).subs(cosx, cos(x))                                                                       
    Out[30]: cos(x) + 1
    

    【讨论】:

    • 感谢您的回答。它非常有用,但仍然不能解决我的问题,考虑到如果表达式略有变化,例如:(cos(x)+1)/(cos(x)**2)**(1/2) ,那么它就不能隔离出“cos(x)/(cos(x)**2)**(1/2)”部分并简化为1+1/(cos(x)**2)**( 1/2) 也不是 1+1/cos(x)。
    • 我尝试了e = (cos(x)+1)/(cos(x)**2)**(S(1)/2),它成功了。我用apart(e.subs(cos(x), cosx).subs(cosx, cos(x))) 得到1 + 1/cos(x)。注意S(1)/2 而不是1/2
    • 这再次有帮助,但是我必须简化太多三角函数(例如 acos(cos(x)); sqrt(sin(x)**2); sqrt(cos(2 *x) + 1); etc.) 只能在 x 的某个域内简化,事情很快就会变得混乱。我认为除了“否定”或“肯定”之外,没有自动将域分配给 x 的方法。
    • 没有一种通用的方式来表达等式中的假设。它的目的是通过新的假设和refine(expr, (0 &lt;= x) &amp; (x&lt;= pi /2)) 之类的东西来实现这一点,但这还没有实现。
    猜你喜欢
    • 2022-06-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多