def setState(self, state): ''' Set the current value for the states and match it to the corresponding symbol Parameters ---------- state: tuple tuple of two elements, (string, numeric) ''' if state is not None: if isinstance(state, (list, tuple)): if isinstance(state[0], tuple): stateOut = list() for i in range(0, len(state)): stateOut.append((self._extractStateSymbol(state[i][0]), state[i][1])) self._state = stateOut else: self._state = self._unrollState(state) elif isinstance(state, numpy.ndarray): self._state = self._unrollState(state) elif ode_utils.isNumeric(state): self._state = self._unrollState(state) else: raise InputError("Input state is of an unexpected type - " + type(state)) else: raise InputError("Input state is of an unexpected type - " + type(state)) return self
def setState(self, state): ''' Set the current value for the states and match it to the corresponding symbol Parameters ---------- state: tuple tuple of two elements, (string, numeric) ''' if state is not None: if isinstance(state, (list, tuple)): if isinstance(state[0], tuple): stateOut = list() for i in range(0, len(state)): stateOut.append((self._extractStateSymbol(state[i][0]), state[i][1])) self._state = stateOut else: self._state = self._unrollState(state) elif isinstance(state, numpy.ndarray): self._state = self._unrollState(state) elif ode_utils.isNumeric(state): self._state = self._unrollState(state) else: raise InputError("Input state is of an unexpected type - " +type(state)) else: raise InputError("Input state is of an unexpected type - " +type(state)) return self
def setStateValue(self, state): ''' Set the current value for the states and match it to the corresponding symbol Parameters ---------- state: array like either a vector of numeric value of a tuple of two elements, (string, numeric) ''' if state is not None: if isinstance(state, (list, tuple)): if isinstance(state[0], tuple): self._state = [self._extractStateSymbol(s[0], s[1]) for s in state] else: self._state = self._unrollState(state) elif isinstance(state, numpy.ndarray): self._state = self._unrollState(state) elif ode_utils.isNumeric(state): self._state = self._unrollState(state) else: raise InputError("Input state is of an unexpected type - " +type(state)) else: raise InputError("Input state is of an unexpected type - " +type(state)) return self
def _unrollState(self, state): ''' Information unrolling from vector to sympy in state ''' stateOut = list() if self._stateList == 1: if ode_utils.isNumeric(state): stateOut.append((self._stateList[0], state)) else: raise InputError("Number of input state not as expected") else: if len(state) == len(self._stateList): for i in range(0, self._numState): stateOut.append((self._stateList[i], state[i])) else: raise InputError("Number of input state not as expected") return stateOut
def simulateJump(self, t, iteration, full_output=False): ''' Simulate the ode using stochastic simulation. It switches between a first reaction method and a :math:`\tau`-leap algorithm internally. Parameters ---------- t: array like the range of time points which we want to see the result of or the final time point iteration: int number of iterations you wish to simulate full_output: bool,optional if we want additional information, simT Returns ------- simX: list of length iteration each with (len(t),len(state)) if t is a vector, else it outputs unequal shape that was record of all the jumps simT: list or :class:`numpy.ndarray` if t is a single value, it outputs unequal shape that was record of all the jumps. if t is a vector, it outputs t so that it is a :class:`numpy.ndarray` instead ''' assert len(self._odeList) == 0, "Currently only able to simulate when only transitions are present" assert numpy.all(numpy.mod(self._x0, 1) == 0), "Can only simulate a jump process with integer initial values" # this determines what type of output we want timePoint = False if ode_utils.isNumeric(t):#, (int, float, numpy.int64, numpy.float64)): finalT = t elif isinstance(t, (list, tuple)): t = numpy.array(t) if len(t) == 1: finalT = t else: finalT = t[-1:] timePoint = True elif isinstance(t, numpy.ndarray): finalT = t[-1:] timePoint = True else: raise InputError("Unknown data type for time") if self._transitionVectorCompile is None: self._compileTransitionVector() # we are going to try the parallel option try: # check the type of parameter we have as input dview, canParallel = self._setupParallel(finalT, iteration, self._paramValue) print "Success in creating parallel environment" if canParallel: #print "Parallel" dview.execute('YList = [ode._jump(t,full_output=True) for i in range(iteration)]') # unroll information simXList = list() simTList = list() for Y in dview['YList']: for simOut in Y: simXList.append(simOut[0]) simTList.append(simOut[1]) #print "Finished" else: print "Failed somewhere" raise SimulationError("Cannot run this in parallel") except Exception as e: #print "Serial" simXList = list() simTList = list() for _i in range(iteration): # now we simulate the jumps simX, simT = self._jump(finalT, full_output=True) # add to list :) simXList.append(simX) simTList.append(simT) # now we want to fix our simulation, if they need fixing that is # print timePoint if timePoint: for _i in range(len(simXList)): # unroll, always the first element # it is easy to remember that we are accessing the first # element because pop is spelt similar to poop and we # all know that your execute first in first out when you # poop! simX = simXList.pop(0) simT = simTList.pop(0) x = self._extractObservationAtTime(simX, simT, t) simTList.append(t) simXList.append(x) # note that we have to remain in list form because the number of # simulation will be different if we are not dealing with # a specific set of time points if full_output: if timePoint: return simXList, t else: return simXList, simTList else: return simXList
def setParameters(self, parameters): ''' Set the values for the parameters already defined. Note that unless the parameters are entered via a dictionary or a two element list,tuple we assume that it is in the order of :meth:`.getParamList` Parameters ---------- parameters: list or equivalent A list which contains two elements (string, numeric value) or just a single array like object ''' # A stupid and complicated type checking procedure. Someone please kill me # when you read this. if parameters is not None: # currently only accept 3 main types here, obviously apart from the # dict type below if isinstance(parameters, (list, tuple, numpy.ndarray)): # length checking, we are assuming here that we always set the full # set of parameters if len(parameters) == self._numParam: if type(parameters) is numpy.ndarray: if parameters.size == self._numParam: parameters = parameters.ravel() else: raise InputError("The number of input parameters is " +str(parameters.size)+ " but " +str(self._numParam)+ " expected") paramOut = dict() else: raise InputError("The number of input parameters is " +str(len(parameters))+ " but " +str(self._numParam)+ " expected") # type checking, making sure that all the different type are accepted if isinstance(parameters[0], tuple): if len(parameters) == self._numParam: for i in range(0, len(parameters)): indexTemp = self._extractParamSymbol(parameters[i][0]) valueTemp = parameters[i][1] paramOut[indexTemp] = valueTemp # we are happy... I guess elif ode_utils.isNumeric(parameters[0]): for i in range(0, len(parameters)): paramOut[self._paramList[i]] = parameters[i] else: raise InputError("Input type should either be a list of tuple with " +"elements (str,numeric) or a list of numeric value") elif isinstance(parameters, dict): # we assume that the key of the dictionary is a string and # the value can be a single value or a distribution if len(parameters) > self._numParam: raise Exception("Too many input parameters") # holder # TODO: change this properly so that there are two different types of parameter # input. One is when we initialize and another when we set new ones if self._parameters is None: paramOut = dict() else: paramOut = self._parameters # extra the key from the parameters dictionary for inParam in parameters: value = parameters[inParam] if ode_utils.isNumeric(value): # get index if isinstance(inParam, sympy.Symbol): paramOut[self._extractParamSymbol(str(inParam))] = value else: paramOut[self._extractParamSymbol(inParam)] = value # and replace only that specific one elif isinstance(value, scipy.stats._distn_infrastructure.rv_frozen): # we always assume that we have a frozen distribution paramOut[self._extractParamSymbol(inParam)] = value.rvs(1)[0] # output of the rv from a frozen distribution is a numpy.ndarray even when # the number of sample is one ## Now we are going make damn sure to record it down! self._stochasticParam = parameters elif isinstance(value, tuple): if callable(value[0]): # using a temporary variable to shorten the line. if isinstance(value[1], dict): paramTemp = value[0](1, **value[1]) else: paramTemp = value[0](1, *value[1]) paramOut[self._extractParamSymbol(inParam)] = paramTemp self._stochasticParam = parameters else: raise InputError("First element should be a callable when using multi " +"argument distribution definition. " +"Type of input was " +str(type(value))) else: raise InputError("Not supported input type for dict() input yet. " +str(type(value))) elif self._numParam == 1: # a single parameter ode and you are not evaluating it analytically! # fair enough! no further comment your honour. paramOut = list() if isinstance(parameters, tuple): paramOut[self._extractParamSymbol(parameters[0])] = parameters[1] elif isinstance(parameters, (int, float)): paramOut[self.getParamList()[0]] = parameters else: raise InputError("Input type should either be a tuple of (str,numeric) " +"or a single numeric value") else: raise InputError("Expecting a dict, list or a tuple input because there are a " +"total of " + str(self._numParam)+ " parameters") else: if self._numParam != 0: raise Warning("Did not set the values of the parameters. Input was None.") else: paramOut= dict() self._parameters = paramOut # unroll the parameter values into the appropriate list # if self._paramValue is None or isinstance(self._paramValue, list): # self._paramValue = dict() self._paramValue = [0] * len(self._paramList) for k, v in self._parameters.iteritems(): index = self.getParamIndex(k) self._paramValue[index] = v return self
def setParameters(self, parameters): ''' Set the values for the parameters already defined. Note that unless the parameters are entered via a dictionary or a two element list,tuple we assume that it is in the order of :meth:`.getParamList` Parameters ---------- parameters: list or equivalent A list which contains two elements (string, numeric value) or just a single array like object ''' # A stupid and complicated type checking procedure. Someone please kill me # when you read this. if parameters is not None: # currently only accept 3 main types here, obviously apart from the # dict type below if isinstance(parameters, (list, tuple, numpy.ndarray)): # length checking, we are assuming here that we always set the full # set of parameters if len(parameters) == self._numParam: if type(parameters) is numpy.ndarray: if parameters.size == self._numParam: parameters = parameters.ravel() else: raise InputError( "The number of input parameters is " + str(parameters.size) + " but " + str(self._numParam) + " expected") paramOut = dict() else: raise InputError("The number of input parameters is " + str(len(parameters)) + " but " + str(self._numParam) + " expected") # type checking, making sure that all the different type are accepted if isinstance(parameters[0], tuple): if len(parameters) == self._numParam: for i in range(0, len(parameters)): indexTemp = self._extractParamSymbol( parameters[i][0]) valueTemp = parameters[i][1] paramOut[indexTemp] = valueTemp # we are happy... I guess elif ode_utils.isNumeric(parameters[0]): for i in range(0, len(parameters)): paramOut[self._paramList[i]] = parameters[i] else: raise InputError( "Input type should either be a list of tuple with " + "elements (str,numeric) or a list of numeric value") elif isinstance(parameters, dict): # we assume that the key of the dictionary is a string and # the value can be a single value or a distribution if len(parameters) > self._numParam: raise Exception("Too many input parameters") # holder # TODO: change this properly so that there are two different types of parameter # input. One is when we initialize and another when we set new ones if self._parameters is None: paramOut = dict() else: paramOut = self._parameters # extra the key from the parameters dictionary for inParam in parameters: value = parameters[inParam] if ode_utils.isNumeric(value): # get index if isinstance(inParam, sympy.Symbol): paramOut[self._extractParamSymbol( str(inParam))] = value else: paramOut[self._extractParamSymbol(inParam)] = value # and replace only that specific one elif isinstance( value, scipy.stats._distn_infrastructure.rv_frozen): # we always assume that we have a frozen distribution paramOut[self._extractParamSymbol( inParam)] = value.rvs(1)[0] # output of the rv from a frozen distribution is a numpy.ndarray even when # the number of sample is one ## Now we are going make damn sure to record it down! self._stochasticParam = parameters elif isinstance(value, tuple): if callable(value[0]): # using a temporary variable to shorten the line. if isinstance(value[1], dict): paramTemp = value[0](1, **value[1]) else: paramTemp = value[0](1, *value[1]) paramOut[self._extractParamSymbol( inParam)] = paramTemp self._stochasticParam = parameters else: raise InputError( "First element should be a callable when using multi " + "argument distribution definition. " + "Type of input was " + str(type(value))) else: raise InputError( "Not supported input type for dict() input yet. " + str(type(value))) elif self._numParam == 1: # a single parameter ode and you are not evaluating it analytically! # fair enough! no further comment your honour. paramOut = list() if isinstance(parameters, tuple): paramOut[self._extractParamSymbol( parameters[0])] = parameters[1] elif isinstance(parameters, (int, float)): paramOut[self.getParamList()[0]] = parameters else: raise InputError( "Input type should either be a tuple of (str,numeric) " + "or a single numeric value") else: raise InputError( "Expecting a dict, list or a tuple input because there are a " + "total of " + str(self._numParam) + " parameters") else: if self._numParam != 0: raise Warning( "Did not set the values of the parameters. Input was None." ) else: paramOut = dict() self._parameters = paramOut # unroll the parameter values into the appropriate list # if self._paramValue is None or isinstance(self._paramValue, list): # self._paramValue = dict() self._paramValue = [0] * len(self._paramList) for k, v in self._parameters.iteritems(): index = self.getParamIndex(k) self._paramValue[index] = v return self
def simulateJump(self, t, iteration, full_output=False): ''' Simulate the ode using stochastic simulation. It switches between a first reaction method and a :math:`\tau`-leap algorithm internally. Parameters ---------- t: array like the range of time points which we want to see the result of or the final time point iteration: int number of iterations you wish to simulate full_output: bool,optional if we want additional information, simT Returns ------- simX: list of length iteration each with (len(t),len(state)) if t is a vector, else it outputs unequal shape that was record of all the jumps simT: list or :class:`numpy.ndarray` if t is a single value, it outputs unequal shape that was record of all the jumps. if t is a vector, it outputs t so that it is a :class:`numpy.ndarray` instead ''' assert len( self._odeList ) == 0, "Currently only able to simulate when only transitions are present" assert numpy.all( numpy.mod(self._x0, 1) == 0), "Can only simulate a jump process with integer initial values" # this determines what type of output we want timePoint = False if ode_utils.isNumeric( t): #, (int, float, numpy.int64, numpy.float64)): finalT = t elif isinstance(t, (list, tuple)): t = numpy.array(t) if len(t) == 1: finalT = t else: finalT = t[-1:] timePoint = True elif isinstance(t, numpy.ndarray): finalT = t[-1:] timePoint = True else: raise InputError("Unknown data type for time") if self._transitionVectorCompile is None: self._compileTransitionVector() # we are going to try the parallel option try: # check the type of parameter we have as input dview, canParallel = self._setupParallel(finalT, iteration, self._paramValue) if canParallel: #print "Parallel" dview.execute( 'YList = [odeS._jump(t,full_output=True) for i in range(iteration)]' ) # unroll information simXList = list() simTList = list() for Y in dview['YList']: for simOut in Y: simXList.append(simOut[0]) simTList.append(simOut[1]) #print "Finished" else: raise SimulationError("Cannot run this in parallel") except Exception as e: #print "Serial" simXList = list() simTList = list() for i in range(iteration): # now we simulate the jumps simX, simT = self._jump(finalT, full_output=True) # add to list :) simXList.append(simX) simTList.append(simT) # now we want to fix our simulation, if they need fixing that is # print timePoint if timePoint: for i in range(len(simXList)): # unroll, always the first element # it is easy to remember that we are accessing the first # element because pop is spelt similar to poop and we # all know that your execute first in first out when you # poop! simX = simXList.pop(0) simT = simTList.pop(0) x = self._extractObservationAtTime(simX, simT, t) simTList.append(t) simXList.append(x) # note that we have to remain in list form because the number of # simulation will be different if we are not dealing with # a specific set of time points if full_output: if timePoint: return simXList, t else: return simXList, simTList else: return simXList