2013-03-02 82 views
4

我正在做一个非常简单的概率计算,从一组A-Z(具有相应的概率x,y,z)获取X,Y,Z的子集。在sympy中分解多边形

因为非常沉重的公式而且,为了处理他们,我想简化(或收集因素 - 我不知道确切的定义)使用sympy这些多项式。

所以..有这个

import sympy as sp 

x, y, z = sp.symbols('x y z') 

expression = (
    x * (1 - x) * y * (1 - x - y) * z + 
    x * (1 - x) * z * (1 - x - z) * y + 

    y * (1 - y) * x * (1 - y - x) * z + 
    y * (1 - y) * z * (1 - y - z) * x + 

    z * (1 - z) * y * (1 - z - y) * x + 
    z * (1 - z) * x * (1 - z - x) * y 
) 

我想要得到的东西(一个非常简单的概率计算得到X,Y,从集AZ的的Z子集与相应的概率X,Y,Z的表达)这样

x * y * z * (6 * (1 - x - y - z) + (x + y) ** 2 + (y + z) ** 2 + (x + z) ** 2) 

聚,在改写的方式有尽可能少的操作(+-***,...)尽可能


我试过factor()collect()simplify()。但结果与我的预期不同。主要是我得到

2*x*y*z*(x**2 + x*y + x*z - 3*x + y**2 + y*z - 3*y + z**2 - 3*z + 3) 

我知道sympy可以结合多项式成简单的形式:

sp.factor(x**2 + 2*x*y + y**2) # gives (x + y)**2 

但如何让sympy到从表达式组合多项式以上?


如果在sympy中这是不可能的任务,可能还有其他的选择吗?

回答

3

把这些方法放在一起恰好给出了一个很好的答案。看看这个策略是否比你产生的方程更经常地工作,或者如果顾名思义这是一次幸运的结果,这将是很有趣的。

def iflfactor(eq): 
    """Return the "I'm feeling lucky" factored form of eq.""" 
    e = Mul(*[horner(e) if e.is_Add else e for e in 
     Mul.make_args(factor_terms(expand(eq)))]) 
    r, e = cse(e) 
    s = [ri[0] for ri in r] 
    e = Mul(*[collect(ei.expand(), s) if ei.is_Add else ei for ei in 
     Mul.make_args(e[0])]).subs(r) 
    return e 

>>> iflfactor(eq) # using your equation as eq 
2*x*y*z*(x**2 + x*y + y**2 + (z - 3)*(x + y + z) + 3) 
>>> _.count_ops() 
15 

BTW,factor_terms和gcd_terms之间的不同之处在于factor_terms将更加努力,拉出来的常用术语,同时保留表达时,原来的结构非常像,你会做手工(即寻找常用术语添加可以拉出)。

>>> factor_terms(x/(z+z*y)+x/z) 
x*(1 + 1/(y + 1))/z 
>>> gcd_terms(x/(z+z*y)+x/z) 
x*(y*z + 2*z)/(z*(y*z + z)) 

对于它的价值,

克里斯

+0

尼斯组合,但它很难理解。你能解释算法/想法吗?顺便说一句,我发现了一个明显的错误:'x *(1-x)* y *(1-x-y)* z + ...' - >'x /(1 - x)* y /(1 - x - y )* z + ...',对于这样的情商你的组合不起作用(我想这是因为明显的事情,但因为我不知道algorythm ....) – akaRem 2013-03-04 21:54:09

1

据我所知,没有什么功能可以做到这一点。我相信这实际上是一个非常难的问题。有关它的一些讨论见Reduce the number of operations on a simple expression

然而,SymPy中有很多简化函数可供您尝试。一个你没有提到过的结果是gcd_terms,它没有进行扩展就将符号化的gcd分解出来。它给出了

>>> gcd_terms(expression) 
x*y*z*((-x + 1)*(-x - y + 1) + (-x + 1)*(-x - z + 1) + (-y + 1)*(-x - y + 1) + (-y + 1)*(-y - z + 1) + (-z + 1)*(-x - z + 1) + (-z + 1)*(-y - z + 1)) 

另一个有用的功能是.count_ops,它计算表达式中的操作数。例如

>>> expression.count_ops() 
47 
>>> factor(expression).count_ops() 
22 
>>> e = x * y * z * (6 * (1 - x - y - z) + (x + y) ** 2 + (y + z) ** 2 + (x + z) ** 2) 
>>> e.count_ops() 
18 

(注意:e.count_ops()是不一样的,你算你自己,因为SymPy自动6*(1 - x - y - z)分发到6 - 6*x - 6*y - 6*z)。

其它有用的功能:

  • cse:执行上表达的公共子表达式消除。有时你可以简化个别部分,然后再将它们放在一起。这也有助于避免重复的计算。

  • horner:将Horner scheme应用于多项式。如果多项式在一个变量中,这将最小化操作次数。

  • factor_terms:类似于gcd_terms。其实我并不完全清楚它们有什么不同。

注意,默认情况下,simplify会尝试一些简化,并返回由count_ops最小的一个。