1

say I have a list of strings representing equations

['', '-protein_0*Kdeg_protein_0+mRNA_0*Ktrans_0', 
'-mRNA_0*Kdeg_mRNA_0+gene_0*Kprod_0', '+mRNA_0*Kdeg_mRNA_0+protein_0*Kdeg_protein_0']

a dictionary with parameter values as floats

{'Kdeg_protein_0': 0.5865674906323503, 'Kdeg_mRNA_0': 0.873345564768431, 'Kprod_0': 13.403565061372824, 'Ktrans_0': 10.37622098808632}

and a dictionary of states

{'Bin': 'y[3]', 'gene_0': 'y[0]', 'mRNA_0': 'y[2]', 'protein_0': 'y[1]'}

I want to get it into the form such that it can be solved by scipy integrate.odeint something like

def ODEs(y,t,input_1,input_2,input_3):  
   Equations   = input_1
   Parameters  = input_2
   States      = input_3


   for key,value in Parameters.items():
     exec(key + '=value')  
   for key,value in States.items():
     exec(key + '=value') 
   for i in range(len(Equations)):
     Equations[i] = eval(Equations[i])   
   return Equations

def main():
    t = numpy.linspace(0,24,24*60)
    y0 = [10,0,0,0]
    y = integrate.odeint(ODEs,y0,t,(GG,PP,LL),)
    print y

I havent been able to work it out, any suggestions to solve this or another approach, it is imperative that the initial data is in list or dictionary form containing strings

at the moment im getting this error: bad operand type for unary +: 'str' for the equations being evaluated

Abhinav Singh Maurya
  • 3,313
  • 8
  • 33
  • 51

2 Answers2

1

EDIT: Made some wrong assumptions about the parameters; a regular expression is needed to guarantee that the state variable names are not contained inside the parameter names.

Your problem is that your equations as written contain undefined variables, you need to substitute the state variables with y[0], y[1] etc. I assume that the equations will always contain valid python syntax?

Your solution should work if you add

import re

to the top of the file, and replace

for key,value in Parameters.items():
   exec(key + '=value')  
for key,value in States.items():
   exec(key + '=value') 

with

for key,value in Parameters.items():
   exec('{} = {}'.format(key,value))

for key,value in States.items():
   for i in range(len(Equations)):
      Equations[i] = re.sub(r"\b%s\b" % key, value, Equations[i])

and sort out the empty string case as you did in your answer. The regex makes sure that a whole word is matched, rather than a substring.

tauroid
  • 46
  • 4
  • thanks for your help you need to indeed replace everything prior to trying to solve it. for some reason it only works when i do this in a seperate function, the solution below works! – Bunnystalker Nov 18 '15 at 13:47
  • 1
    Just tested it and realised I made some pretty basic mistakes :) I think you need the regex bit or you will end up with stuff like Kdeg_y[1] depending on your substitution order. My solution should work but obviously it's better to keep your strings constant like you did in your answer. If speed is an issue you might want to look into generating functions from your strings eg `exec('def eq{}(y):\n {}\n'.format(i,Equation[i]))` – tauroid Nov 18 '15 at 14:21
  • thanks! the string to function is nice, speed is a major issue indeed – Bunnystalker Nov 19 '15 at 08:47
1

for some reason it is tricky to translate your strings to variables whilst trying to build a function for an ODE solver, can only think of replacing everything seperately with floats and matrix indices first and plugging that into a model building function that builds a model that can be solved by odeint

def Equation_Builder(input_1,input_2,input_3):  
    Equations   = input_1
    Parameters  = input_2
    States      = input_3   
    for key,value in Parameters.items(): 
       exec('{} = {}'.format(key,value))
    print Parameters
    for i in range(len(Equations)):
      for key,value in States.items():
          Equations[i] = Equations[i].replace(key,value)
    for i in range(len(Equations)):          
      for key,value in Parameters.items():
          Equations[i]  = Equations[i].replace(key,value)
    for i in range(len(Equations)):
        if Equations[i] == '':
            Equations[i] ='0'
    return Equations  

def Model_Builder(input_1):
    Equations = input_1
    def model(y,t):
        dydt = numpy.zeros(len(Equations))
        for i in range(len(Equations)):
            dydt[i] = eval(''.join(Equations[i]))
        return dydt
    return model

def main():
    t = numpy.linspace(0,24,24*60)
    y0 = [10,0,0,0]
    model = Model_Builder(Equations)
    y = integrate.odeint(model,y0,t)
    print y