2016-06-04 2 views
1

Я пытаюсь создать функцию, которая может генерировать систему уравнений, которые решаются в отдельной программе. Уравнения генерируются из дерева изотоп распадается, но для простоты я имею следующее дерево:Создать систему уравнений

decay tree

Так что это может быть сделано в 2-х возможных цепочек распада:

[(A,0,1,5), (B,1,.4,4), (C,0,.4,0)] 

[(A,0,1,5), (B,1,.6,6), (C,0,.6,0)] 

где формат (вид, число, вероятность распада, период полураспада). Я пытаюсь сделать функцию, которая автоматически создаст систему уравнений для дерева распада, которая может быть более сложной, чем эта. Правила такие же, хотя для любого дерева:

Для некоторых видов X с родителями y_1, Y_2, ..., Y_n:

X_final = сумма для каждого из родительских видов (вероятность распада Y_n -> X * количество Y_n/полураспада Y_n) - сумма X/полураспада X, который может быть представлен в виде:

equation

и каждый вид в цепи будет иметь свое собственное уравнение будет решил позже. Так что для этого, я хочу следующую систему уравнений:

A_f = - A_i/5 
B1_f = .4 * A_i/5 - B1_i/4 
B2_f = .6 * A_i/5 - Β2_i/6 
C = B1_i/4 + B2_i/6 

Кроме того, если период полураспада 0, это означает, что она стабильна. В настоящее время я создаю систему уравнений, создавая словарь строк, но я думаю, что есть лучший способ сделать это. Я планирую превратить строки в переменные позже, после того как я создам систему со строками. Вот мой код:

A = 'A' 
B = 'B' 
C = 'C' 
D = 'D' 

chain1 = [(A,0,1,5),(B,1,.4,4),(C,0,.4,0),(D,0,.4,0)] 
chain2 = [(A,0,1,5),(B,2,.6,6),(C,0,.6,0),(D,0,.6,0)] 
master_chain = [chain1, chain2] 

def equation_builder(master_chain): 
    master_equations = {} 
    m = 0 
    for chain in master_chain: 
     n = 0 
     for item in chain: 
      if item == chain[0]: 
       equation = {str(item[0]) + str(item[1]) + 'f' :\ 
       '-' + str(item[0]) + str(item[1]) + 'i/' + str(item[3])} 
       master_equations.update(equation) 
      elif str(item[0])+str(item[1])+'f' not in master_equations: 
       equation = {str(item[0]) + str(item[1]) + 'f' :\ 
       str(item[2]/chain[n-1][2])+str(chain[n-1][0]) + 
       str(chain[n-1][1])+'i/' + str(chain[n-1][3])+\ 
       '-'+str(item[0])+str(item[1])+'i/'+str(item[3])} 
       master_equations.update(equation) 
      elif str(item[0])+str(item[1])+'f' in master_equations \ 
      and master_chain[m-1][n-1] != master_chain[m][n-1]: 
       old_equation = master_equations[str(item[0])+str(item[1])+'f'] 
       new_equation = old_equation + '+' +\ 
       str(item[2]/chain[n-1][2])+str(chain[n-1][0]) +\ 
       str(chain[n-1][1])+'i/' + str(chain[n-1][3]) 
       equation = {str(item[0])+str(item[1])+'f' : new_equation} 
       master_equations.update(equation) 
      n += 1 
     m += 1 

    return master_equations 

if __name__ == '__main__': 
    print equation_builder(master_chain) 
+0

Как отдельная программа принимает отформатированные уравнения? –

ответ

4

Использовать SymPy. SymPy - это набор инструментов для символических вычислений и очень хорошо подходит для этого варианта использования. Вы можете создать символ, используя A = sympy.Symbol("A"), а затем используйте A в выражении, как будто вы используете любую переменную. Например, если A и B являются символами, тогда, если вы напишете C=A*exp(B), print C выведет A*exp(B). Используя свойство выражения args, вы также можете получить доступ к представлению дерева синтаксиса любого выражения, которое может быть полезно, если вы хотите продолжить обработку уравнений.

Вот пример, используя свой график (я не совсем понимаю, как вы пришли ваши результаты, так что это может понадобиться корректировка, но это должно быть достаточно, чтобы получить представление):

import sympy as sp 

A, B1, B2, C = sp.symbols("A, B1, B2, C") 

chain1 = [(A,0,1,5),(B1,1,.4,4),(C,0,0.4,0)] 
chain2 = [(A,0,1,5),(B2,2,.6,6),(C,0,0.6,0)] 
master_chain = [chain1, chain2] 

finals = {} 
for subchain in master_chain: 
    for i, (species, number, decay_prob, half_life) in enumerate(subchain): 
     input_species = sp.Symbol(str(species) + "_i") 
     if species not in finals: 
      finals[species] = -input_species/half_life if half_life else 0 
     if i < len(subchain) - 1: 
      (other_species, other_number, other_decay_prob, other_half_life) = subchain[i+1] 
      if other_species not in finals: 
       finals[other_species] = -sp.Symbol(str(other_species) + "_i")/other_half_life if other_half_life else 0 
      finals[other_species] += input_species * decay_prob/half_life 

print finals 

Выход

{C: 0.1*B1_i + 0.1*B2_i, B2: A_i/5 - B2_i/6, A: -A_i/5, B1: A_i/5 - B1_i/4} 

Обратите внимание, что Symbol("x") == Symbol("x"), например, символы идентифицируются по их строковому представлению, так что вы смело можете воссоздать символ каждый раз, когда вам это нужно.

+0

Будет ли это легко изменяться для сколь угодно больших цепей, которые могут включать в себя десятки символов, которые я не знаю заранее? Моя программа автоматически вычисляет и создает цепочки, которые могут быть длинными. Это также означает, что я знаю только первый символ при запуске программы. – greenthumbtack

+0

Несомненно.Я использовал этот подход один раз, чтобы найти явные выражения для устойчивых видов в механизме реакции с ~ 150 видами и несколькими (автоматическими) квазистационарными предположениями, поэтому в обстановке, очень похожей на вашу. Работает как прелесть, хотя если вы запустите «решаете» sympy на вашей конечной системе для решения некоторых переменных, это может стать немного медленным для очень больших систем. Пока вы хотите генерировать выражения, я сомневаюсь, что существует * соответствующий * предел. – Phillip

+0

Как я могу это сделать без знания вида заранее? Как функция, которая автоматически создавала симплексные символы и возвращала список всех из них. Например, если у меня есть список строковых переменных str_var = ['a', 'b', 'c', ... 'n'] и нужна функция, которая автоматически создает симплексный символ для каждого из них? – greenthumbtack

Смежные вопросы