Python: Список алгебраических упрощений

Привет, я пытаюсь получить общие условия списка, чтобы упростить его, например, если у меня есть список:

List=[['1','A1','B1','Kc','Ka'],['1','A1','B1','D2','Kc','Ka'],
['-1','A1','B1','D1','Kc','Ka'],['1','A1','B1','D1','KD','Ka'],
['-1','B1','D1','C1','Kc','Ka','KF'],['1','B1','D1','F1','Kc','Kz','Kl']]    

есть ли какая-нибудь функция, которая могла бы дать мне в результате:

List_output=[['A1', 'B1', [['D1', [['KD', 'Ka'],
['-1', 'Ka', 'Kc']]], ['Ka', 'Kc'], ['D2', 'Ka', 'Kc']]],
['B1', 'D1', [['F1', 'Kc', 'Kl', 'Kz'], ['-1', 'C1', 'KF', 'Ka', 'Kc']]]]

То, что я в основном хочу сделать, это алгебраическая редукция.

(A1 B1 Kc Ka + A1 B1 D2 Kc Ka - A1 B1 D1 Kc Ka + A1 B1 D1 KD Ka -
B1 D1 C1 Kc Ka KF + B1 D1 F1 Kc Kz Kl ) ->
A1B1[D1[-KcKa + KDKa] + D2KcKa +KcKa] + B1D1[-C1[KcKaKF] + F1[KcKzKl]]  

Единственное требование для упрощения состоит в том, что все упрощенные термины должны зависеть от суммы или остальных K. Другими словами, все должно быть функцией линейной комбинации K: [-KcKa + KDKa]; [KcKaKF]; [['-1','Kc','Ka'],['+1','KD','Ka']].

Я пытаюсь использовать SymPy, но проблема заключается в том, что термины для сокращения поступают откуда-то еще, поэтому я никогда не знаю, какими будут символы. Чтобы использовать SymPy, вам нужно объявить символы, верно? Любая идея о том, как я могу решить эту проблему?


person user3671704    schedule 03.07.2016    source источник
comment
Очень интересный вопрос. Есть ли у вас какие-либо требования к тому, чтобы решение было каким-то образом оптимальным, или любое хорошее упрощение сработает?   -  person Yash Tewari    schedule 03.07.2016
comment
Ваша проблема не имеет однозначного решения: подвыражения могут быть факторизованы более чем одним эквивалентным способом.   -  person Francesco Bonazzi    schedule 03.07.2016
comment
Единственное требование состоит в том, что все упрощения должны зависеть от суммы или остальных K. Другими словами, все должно быть функцией линейной комбинации К.   -  person user3671704    schedule 03.07.2016
comment
@user3671704 user3671704 Пожалуйста, отредактируйте свой вопрос, чтобы включить это требование.   -  person Yash Tewari    schedule 03.07.2016
comment
Не связано ли это случайно со скоростью химической реакции? (просто предполагаю)   -  person Francesco Bonazzi    schedule 03.07.2016
comment
@FrancescoBonazzi да Это связано с химией, но не с кинетикой, а с функционализацией спектральных сигналов и переходом. A, B,... - это моды, а K - это сигналы в спектрометре.   -  person user3671704    schedule 03.07.2016
comment
horner становится довольно близко к тому, что вы хотите (после преобразования в выражение SymPy, как в ответе Франческо). По какой-то причине он не учитывает член D1 из последнего выражения должным образом.   -  person asmeurer    schedule 06.07.2016
comment
Некоторое обсуждение этого здесь github.com/sympy/sympy/issues/11349   -  person asmeurer    schedule 09.07.2016


Ответы (2)


Я думаю, вы знаете, какие алгебраические манипуляции вы хотите сделать, но вы зациклены на том, чтобы получить символы «K» из sympy? Sympy довольно хорошо угадывает имена переменных. Вы можете просто построить выражение:

In [1]: import sympy

In [2]: List=[['1','A1','B1','Kc','Ka'],['1','A1','B1','D2','Kc','Ka'],['-1','A
   ...: 1','B1','D1','Kc','Ka'],['1','A1','B1','D1','KD','Ka'],['-1','B1','D1',
   ...: 'C1','Kc','Ka','KF'],['1','B1','D1','F1','Kc','Kz','Kl']]    

In [3]: expression = sympy.Add(*[sympy.Mul(*[sympy.S(y) for y in x]) for x in L
   ...: ist] )

In [4]: expression
Out[4]: A1*B1*D1*KD*Ka - A1*B1*D1*Ka*Kc + A1*B1*D2*Ka*Kc + A1*B1*Ka*Kc - B1*C1*D1*KF*Ka*Kc + B1*D1*F1*Kc*Kl*Kz

И затем получить список символов:

In [5]: all_symbols = [x for x in expression.atoms() if type(x)==sympy.Symbol]

In [6]: all_symbols
Out[6]: [Kc, B1, KF, A1, Kz, Ka, D1, C1, F1, D2, KD, Kl]

Когда у вас есть список символов, легко получить те, которые начинаются с «K» или нет:

In [7]: solvefor = [x for x in all_symbols if str(x)[0]!="K"]

In [8]: solvefor
Out[8]: [B1, A1, D1, C1, F1, D2]

In [9]: sympy.horner(expression, wrt=solvefor)
Out[9]: B1*(A1*(D1*(KD*Ka - Ka*Kc) + D2*Ka*Kc + Ka*Kc) + D1*(-C1*KF*Ka*Kc + F1*Kc*Kl*Kz))
person RLC    schedule 02.08.2016

Прежде всего, преобразуйте свой список в выражение SymPy:

In [1]: List=[['1','A1','B1','Kc','Ka'],['1','A1','B1','D2','Kc','Ka'],['-1','A1','B1','D1','Kc','Ka'],['1','A1','B1','D1','KD','Ka'],['-1','B1','D1','C1','Kc','Ka','KF'],['1','B1','D1','F1','Kc','Kz','Kl']]

In [2]: list_add_mul = sympify(List)

In [4]: expr = Add(*map(lambda x: Mul(*x), list_add_mul))

In [5]: expr
Out[5]: 
A₁⋅B₁⋅D₁⋅KD⋅Ka - A₁⋅B₁⋅D₁⋅Ka⋅Kc + A₁⋅B₁⋅D₂⋅Ka⋅Kc + A₁⋅B₁⋅Ka⋅Kc - B₁⋅C₁⋅D₁⋅KF⋅K
a⋅Kc + B₁⋅D₁⋅F₁⋅Kc⋅Kl⋅Kz

Теперь expr — это выражение SymPy, с которым вы хотите работать. Если вы просто хотите заменить некоторые значения, используйте .subs:

Не забудьте определить символы, которые вы собираетесь использовать:

>>> var("Ka, Kc, Kz")

Затем вы можете заменить:

In [6]: expr.subs({Ka: 25.0, Kc: 7.0, Kz: 3.5})
Out[6]: 
25.0⋅A₁⋅B₁⋅D₁⋅KD - 175.0⋅A₁⋅B₁⋅D₁ + 175.0⋅A₁⋅B₁⋅D₂ + 175.0⋅A₁⋅B₁ - 175.0⋅B₁⋅C₁
⋅D₁⋅KF + 24.5⋅B₁⋅D₁⋅F₁⋅Kl

В противном случае вы можете попытаться определить правило подстановки для ваших переменных. Например, поместите их в dict:

{
    Ka: ... ,
    Kc: ... ,
    KD: ... ,
    KF: ... ,
}

Вы должны заменить точки подходящим выражением, содержащим новые переменные. Эти новые переменные должны представлять собой комбинации ваших констант K.

Например: c1 = -Kc*Ka + KD*Ka, _c2 = ... _, то вы инвертируете эти уравнения.

В вашем случае кажется, что ваши выражения не могут быть правильно инвертированы:

>>> solve([Eq(-Kc*Ka + KD*Ka, c1 ), Eq(Kc*Ka*KF, c2), Eq(-Kc*Ka + KD*Ka, c3), Eq(Kc*Ka*KF, c4)], Ka, Kc, KD, KF)
[]
person Francesco Bonazzi    schedule 04.07.2016
comment
Я сделал все шаги, но когда я попробовал команду expr.subs({Ka: 25.0, Kc: 7.0, Kz: 3.5}), я получил: имя «Ka» не определено - person user3671704; 06.07.2016
comment
Вам нужно определить все переменные, которые вы собираетесь использовать. Я обновил ответ. - person Francesco Bonazzi; 06.07.2016