2013-03-02 2 views
4

Я делаю очень простые вычисления вероятности получения подмножества X, Y, Z из множества A-Z (с соответствующими вероятностями x, y, z).Факторинговые полисы в sympy

И из-за очень тяжелых формул для того, чтобы справиться с ними, я пытаюсь упростить (или собирать или фактор - я не знаю точное определение) эти полиномиальные выражения с использованием SymPy.

Так .. имея это (очень простое выражение для вычисления вероятности получения подмножества X, Y, Z из множества AZ с соответствующими вероятностями х, у, г)

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 * 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 

Кстати, разница между 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)) 

Для чего это стоит,

Chris

+0

Nice комбо, но это очень трудно понять. Не могли бы вы объяснить алгоритм/идею? BTW Я обнаружил очевидную ошибку: 'x * (1 - x) * y * (1 - x - y) * z + ...' -> 'x/(1 - x) * y/(1 - x - y) * z + ... ', и для такого eq ваша комбо не работает (я полагаю, что это из-за очевидных вещей, но так как я не знаю алгоризма ....) – akaRem

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.