Beispiel #1
0
def test_BlockMatrix_Inverse_execution():
    k, n = 2, 4
    dtype = 'float32'
    A = sympy.MatrixSymbol('A', n, k)
    B = sympy.MatrixSymbol('B', n, n)
    inputs = A, B
    output = B.I*A

    cutsizes = {A: [(n/2, n/2), (k/2, k/2)],
                B: [(n/2, n/2), (n/2, n/2)]}
    cutinputs = [sympy.blockcut(i, *cutsizes[i]) for i in inputs]
    cutoutput = output.subs(dict(zip(inputs, cutinputs)))

    dtypes = dict(zip(inputs, [dtype]*len(inputs)))
    f = theano_function(inputs, [output], dtypes=dtypes)
    fblocked = theano_function(inputs, [sympy.block_collapse(cutoutput)],
                               dtypes=dtypes)

    import numpy
    ninputs = [numpy.random.rand(*x.shape).astype(dtype) for x in inputs]
    ninputs = [numpy.arange(n*k).reshape(A.shape).astype(dtype),
               numpy.eye(n).astype(dtype)]
    ninputs[1] += numpy.ones(B.shape)*1e-5

    assert numpy.allclose(f(*ninputs), fblocked(*ninputs), rtol=1e-5)
Beispiel #2
0
def test_theano_function_kwargs():
    import numpy as np
    f = theano_function([x, y, z], [x + y],
                        dim=1,
                        on_unused_input='ignore',
                        dtypes={
                            x: 'float64',
                            y: 'float64',
                            z: 'float64'
                        })
    assert np.linalg.norm(f([1, 2], [3, 4], [0, 0]) -
                          np.asarray([4, 6])) < 1e-9

    f = theano_function([x, y, z], [x + y],
                        dtypes={
                            x: 'float64',
                            y: 'float64',
                            z: 'float64'
                        },
                        dim=1,
                        on_unused_input='ignore')
    xx = np.arange(3).astype('float64')
    yy = 2 * np.arange(3).astype('float64')
    zz = 2 * np.arange(3).astype('float64')
    assert np.linalg.norm(f(xx, yy, zz) - 3 * np.arange(3)) < 1e-9
Beispiel #3
0
def lambdify(args, expr, subs=None, simplify=True):
    """
    call to lambdify with chosen options
    """
    vector_expr = hasattr(expr, 'index')
    if subs is not None:
        if vector_expr:
            for i, e in enumerate(expr):
                expr[i] = e.subs(subs)
        else:
            expr = expr.subs(subs)
    if simplify:
        expr = simp(expr)
    expr = sympy.sympify(expr)
    # array2mat = [{'ImmutableMatrix': numpy.matrix}, 'numpy']

    try:
        if vector_expr:
            expr_lambda = theano_function(args, expr,
                                          on_unused_input='ignore')
        else:
            expr_lambda = theano_function(args, [expr],
                                          on_unused_input='ignore')
    except:
        expr_lambda = sympy.lambdify(args,
                                     expr,
                                     dummify=False,
                                     modules='numpy')
    return expr_lambda
    def prepareStatment(self):
        A = MatrixSymbol('A',*self.A.shape)
        H = MatrixSymbol('H',*self.H.shape)
        x = MatrixSymbol('x',*self.x.shape)
        P = MatrixSymbol('P',self.H.shape[1],self.H.shape[1])
        Q = MatrixSymbol('Q',*self.Q.shape)
        R = MatrixSymbol('R',*self.R.shape)
        I = MatrixSymbol('I',max(x.shape),max(x.shape))
        measurement = MatrixSymbol('measurement', *(H * x).shape)
        #Update
        y = measurement - H * x
        S = H * P * H.T + R
        K = P * H.T * S.I
        up_x = x + K * y
        up_P = (I - K * H) * P

        inputs = [x,P,H,R,I,measurement]
        outputs = [up_x, up_P]
        dtypes = {inp: 'float64' for inp in inputs}

        self.update = theano_function(inputs, outputs, dtypes=dtypes)
        #Predict
        pre_x = A * x
        pre_P = A * P * A.T + Q

        inputs = [A,x,P,Q]
        outputs = [pre_x, pre_P]
        dtypes = {inp: 'float64' for inp in inputs}

        self.predict = theano_function(inputs, outputs, dtypes=dtypes)
Beispiel #5
0
 def __generate_theano_functions(self):
     self.rates_theano = theano_function(self.variables.reference +
                                         self.parameters.reference,
                                         [t.rate for t in self.transitions],
                                         on_unused_input='ignore')
     self.vector_field_theano = theano_function(self.variables.reference +
                                                self.parameters.reference,
                                                self._vector_field_sympy,
                                                on_unused_input='ignore')
Beispiel #6
0
def test_theano_function_numpy():
    import numpy as np
    f = theano_function([x, y], [x+y], dim=1)
    assert np.linalg.norm(f([1, 2], [3, 4]) - np.asarray([4, 6])) < 1e-9

    f = theano_function([x, y], [x+y], dtypes={x: 'float64', y: 'float64'},
                                     dim=1)
    xx = np.arange(3).astype('float64')
    yy = 2*np.arange(3).astype('float64')
    assert np.linalg.norm(f(xx, yy) - 3*np.arange(3)) < 1e-9
Beispiel #7
0
def test_theano_function_kwargs():
    import numpy as np
    f = theano_function([x, y, z], [x+y], dim=1, on_unused_input='ignore',
            dtypes={x: 'float64', y: 'float64', z: 'float64'})
    assert np.linalg.norm(f([1, 2], [3, 4], [0, 0]) - np.asarray([4, 6])) < 1e-9

    f = theano_function([x, y, z], [x+y],
                        dtypes={x: 'float64', y: 'float64', z: 'float64'},
                        dim=1, on_unused_input='ignore')
    xx = np.arange(3).astype('float64')
    yy = 2*np.arange(3).astype('float64')
    zz = 2*np.arange(3).astype('float64')
    assert np.linalg.norm(f(xx, yy, zz) - 3*np.arange(3)) < 1e-9
Beispiel #8
0
def theano_lambdify(args, expr):
    """
Lambdify expression expr w.r.t arguments args using theano.
    """

    theano_opts = {'on_unused_input': 'ignore', 'allow_input_downcast': False}

    # detect if expression is a vector
    if isinstance(expr, types.vector_types):
        # Below converts output of 1D vector functions with length 1...
        # ... back to 1D numpy array, because the default is 0D array (scalar).
        if len(expr) == 1:

            def getslice(f):
                return numpy.asarray(f, dtype=DTYPE)[numpy.newaxis]
        else:

            def getslice(f):
                return numpy.asarray(f, dtype=DTYPE)
    else:
        expr = [
            expr,
        ]

        def getslice(f):
            return numpy.asarray(f, dtype=DTYPE)

    # theano does not accept sympy numbers as output...
    expr_lambda = theano_function(args, expr, **theano_opts)

    return lambda *args: getslice(expr_lambda(*args))
Beispiel #9
0
def sympy_theanify(sympy_expr, symbols=()):
    if isinstance(sympy_expr, Expr):
        if not symbols:
            symbols = sympy_expr.free_symbols
        return theano_function(symbols, [sympy_expr])
    else:
        return lambda **kwargs: sympy_expr
Beispiel #10
0
def theano_lambdify(args, expr):
    """
Lambdify expression expr w.r.t arguments args using theano.
    """

    theano_opts = {'on_unused_input': 'ignore',
                   'allow_input_downcast': False}

    # detect if expression is a vector
    if isinstance(expr, types.vector_types):
        # Below converts output of 1D vector functions with length 1...
        # ... back to 1D numpy array, because the default is 0D array (scalar).
        if len(expr) == 1:
            def getslice(f):
                return numpy.asarray(f, dtype=DTYPE)[numpy.newaxis]
        else:
            def getslice(f):
                return numpy.asarray(f, dtype=DTYPE)
    else:
        expr = [expr, ]

        def getslice(f):
            return numpy.asarray(f, dtype=DTYPE)

    # theano does not accept sympy numbers as output...
    expr_lambda = theano_function(args, expr, **theano_opts)

    return lambda *args: getslice(expr_lambda(*args))
Beispiel #11
0
    def _theanoize(self, outputs):

        self.define_inputs()

        old_check_input = theano.config.check_input
        old_allow_gc = theano.config.allow_gc
        try:
            # This affects compilation and removes the input check at each step.
            theano.config.check_input = False

            # Disable Theano garbage collection to lower the number of allocations.
            theano.config.allow_gc = False

            f_imp = theano_function(self.inputs,
                                    outputs,
                                    on_unused_input='ignore',
                                    mode=theano.Mode(linker='c'))
        finally:
            theano.config.check_input = old_check_input
            theano.config.allow_gc = old_allow_gc

        # While denoting an input as trusted lowers Theano overhead:
        #     f.trust_input = True
        # we can bypass additional overhead with the following function:
        def f(*args):
            for i in range(len(args)):
                f_imp.input_storage[i].storage[0] = args[i]
            f_imp.fn()
            return [f_imp.output_storage[i].data for i in range(len(outputs))]

        return f
    def _theanoize(self, outputs):

        self.define_inputs()

        old_check_input = theano.config.check_input
        old_allow_gc = theano.config.allow_gc
        try:
            # This affects compilation and removes the input check at each step.
            theano.config.check_input = False

            # Disable Theano garbage collection to lower the number of allocations.
            theano.config.allow_gc = False

            f_imp = theano_function(self.inputs, outputs,
                                    on_unused_input='ignore',
                                    mode=theano.Mode(linker='c'))
        finally:
            theano.config.check_input = old_check_input
            theano.config.allow_gc = old_allow_gc

        # While denoting an input as trusted lowers Theano overhead:
        #     f.trust_input = True
        # we can bypass additional overhead with the following function:
        def f(*args):
            for i in range(len(args)):
                f_imp.input_storage[i].storage[0] = args[i]
            f_imp.fn()
            return [f_imp.output_storage[i].data for i in range(len(outputs))]

        return f
Beispiel #13
0
    def make_theano_fns_of_d1d2xw(self, dg_first, dg_second):

        args = self.normal_x_s_d.values() + self.normal_w_s_d.values() + \
            self.param_sym_dict.values()

        args_values_x = [x.subs(self.normal_xw_s_ss_values_d)
                         for x in self.normal_x_s_d.values()]

        args_values_w = [w.subs(self.normal_xw_s_ss_values_d)
                         for w in self.normal_w_s_d.values()]

        args_values_p = [p.subs(self.par_to_values_dict)
                         for p in self.param_sym_dict.values()]

        args_values = args_values_x + args_values_w + args_values_p

        dg_first_th = theano_function(args, dg_first, on_unused_input='ignore')
        dg_second_th = theano_function(
            args, dg_second, on_unused_input='ignore')

        return dg_first_th, dg_second_th, args_values
Beispiel #14
0
    def _theanoize(self, outputs):

        self.define_inputs()

        f = theano_function(self.inputs, outputs, on_unused_input='ignore')

        # Theano will run faster if you trust the input. I'm not sure
        # what the implications of this are. See:
        # http://deeplearning.net/software/theano/tutorial/faq.html#faster-small-theano-function
        # Note that map(np.asarray, np.hstack(args)) is required if
        # trust_input is True. If it is False, then it will sanitize the
        # inputs. I'm not sure which one is faster.
        f.trust_input = True

        return f
Beispiel #15
0
    def _theanoize(self, outputs):

        self.define_inputs()

        f = theano_function(self.inputs, outputs, on_unused_input='ignore')

        # Theano will run faster if you trust the input. I'm not sure
        # what the implications of this are. See:
        # http://deeplearning.net/software/theano/tutorial/faq.html#faster-small-theano-function
        # Note that map(np.asarray, np.hstack(args)) is required if
        # trust_input is True. If it is False, then it will sanitize the
        # inputs. I'm not sure which one is faster.
        f.trust_input = True

        return f
 def __init__(self, var_names_and_syms={}, dict_or_expr={}):
     if hasattr(dict_or_expr, 'keys'):
         for k, v in dict_or_expr.items():
             dict_or_expr[k] = CompyledFunc(var_names_and_syms=var_names_and_syms, dict_or_expr=v)
         self.Compyled = dict_or_expr
     elif is_non_atomic_sympy_expr(dict_or_expr):
         self.Vars = tuple(var for var, symbol in var_names_and_syms.items()
                           if symbol and not(isinstance(symbol, FLOAT_TYPES)))
         inputs = (var_names_and_syms[var] for var in self.Vars)
         if use_theano:
             self.Compyled = theano_function(inputs, (dict_or_expr,), allow_input_downcast=True)
         else:
             self.Compyled = ufuncify(inputs, dict_or_expr)
     else:
         self.Compyled = sympy_to_float(dict_or_expr)
def linearize_gpc_dynamics_noinit_theano(dynamics, x, u, n_uncert, p,
                                         input_states):
    n_states = x.shape[0]

    Hp = GaussHermitePC(n_uncert - n_states, p)
    l = Hp.shape[0]

    xc_vals = zeros(l, n_states)
    for i in range(0, n_states):
        xc_vals[:, i] = Matrix(
            [symbols('x' + str(i) + str(j)) for j in range(0, l)])

    states = xc_vals.T.reshape(n_states * l, 1)

    dynH = Matrix(dynamics)
    Aj = dynH.jacobian(states)
    Bj = dynH.jacobian(u)
    Cj = dynH - Aj * states - Bj * u

    A = theano_function(input_states, Aj, on_unused_input='ignore')
    B = theano_function(input_states, Bj, on_unused_input='ignore')
    C = theano_function(input_states, Cj, on_unused_input='ignore')

    return A, B, C  #theano functions for linearization
Beispiel #18
0
def expr_to_theano(expr, ndims, *args, **subs):
    from sympy.printing.theanocode import theano_function

    f_sym = sp.lambdify(args, subs_dict(expr, subs), modules=("sympy", ))

    subbed_expr = subs_dict(expr, subs)
    dims = {arg: ndims for i, arg in enumerate(args)}

    dtypes = {arg: 'float64' for arg in args}

    ph = sp.Symbol('PLACEHOLDER')
    # Compile the function with the dummpy var.
    f_th = theano_function(
        [ph, *args],
        [ph + subbed_expr],
        # If args is longer than grid, repeat last dim in grid
        # e.g. theta, phi share a dimension (p)
        # Five args, but only four dimensions
        dims={
            ph: ndims,
            **dims
        },
        dtypes={
            ph: 'float64',
            **dtypes
        },
        on_unused_input='ignore')

    # Set placeholder to zero and
    # broadcast before giving to theano
    @fu.wraps(f_sym)
    def f_wrap(*inner_args):
        # Broadcast in case inner_args
        # are not already broadcasted.
        # If they are, that's fine too.
        bcast_shape = np.shape(sum(inner_args))
        bcast_args = [np.broadcast_to(arg, bcast_shape) for arg in inner_args]
        print("f_th_wrap got args:")
        for i, inner_arg in enumerate(inner_args):
            print("var {}: type={}, shape={}".format(i, type(inner_arg),
                                                     np.shape(inner_arg)))
            print("bcast var {}: type={}, shape={}".format(
                i, type(bcast_args[i]), np.shape(bcast_args[i])))
        phn = np.zeros_like(bcast_args[0])
        return f_th(phn, *bcast_args)

    return f_wrap
Beispiel #19
0
def obs_term_gradient_optimization(obs_gradient,
                                   background_data_vector,
                                   smallest_gradient=0.001,
                                   iteration_step=0.001):
    # def _get_haha(x):
    #    a = obs_gradient.subs({analysis_increment_vector_symbol: x})
    #    return a
    obs_term_gradient_value = numpy.matrix(
        999.0 * numpy.ones(background_data_vector.shape))
    #analysis_increment_vector = sympy.Matrix(numpy.zeros(background_data_vector.shape))
    analysis_increment_vector = numpy.matrix(
        numpy.zeros(background_data_vector.shape))

    analysis_increment_vector_symbol = sympy.MatrixSymbol(
        'analysis_increment_symbol', len(background_data_vector), 1)
    # from scipy import optimize
    # optimize.minimize(_get_haha, numpy.zeros(background_data_vector.shape), method="CG")

    # a = _get_haha(x)
    dtypes = {inp: 'float8' for inp in analysis_increment_vector_symbol}

    print 'create func'
    f = theano_function([analysis_increment_vector_symbol], [obs_gradient],
                        dtypes=dtypes)
    #f=sympy.lambdify(analysis_increment_vector_symbol, obs_gradient, 'numpy')
    print 'created func'
    #f=sympy.lambdify(analysis_increment_vector_symbol, obs_gradient, 'sympy')
    n = 0
    while (obs_term_gradient_value.sum() <= -smallest_gradient
           or obs_term_gradient_value.sum() > smallest_gradient):
        # obs_term_gradient_value =  obs_gradient.subs({analysis_increment_vector_symbol: analysis_increment_vector}).doit()
        # f=sympy.lambdify(analysis_increment_vector_symbol, obs_gradient, 'sympy')
        #obs_term_gradient_value = f(analysis_increment_vector)
        obs_term_gradient_value = f(analysis_increment_vector)

        analysis_increment_vector = analysis_increment_vector - iteration_step * obs_term_gradient_value

        print n, obs_term_gradient_value.sum()

        n = n + 1

        if n > 2000:
            break

    # print analysis_increment_vector
    # print background_data_vector + analysis_increment_vector
    return background_data_vector + analysis_increment_vector
Beispiel #20
0
    def prepareStatment(self):
        measurement = MatrixSymbol('measurement', *(self.H * self.x).shape)
        #Update
        y = measurement - self.H * self.x
        S = self.H * self.P * self.H.T + self.R
        K = self.P * self.H.T * S.I
        upx = self.x + K * y
        upP = self.I - K * self.H
        #Predict
        new_x = self.A * upx
        new_P = self.A * upP * self.A.T + self.Q

        inputs = [self.A,self.x,self.P,self.H,self.R,self.I,self.Q,measurement]
        outputs = [new_x, new_P]
        dtypes = {inp: 'float64' for inp in inputs}

        self.theano_update = theano_function(inputs, outputs, dtypes=dtypes)
Beispiel #21
0
 def __init__(self, var_names_and_syms={}, dict_or_expr={}):
     if hasattr(dict_or_expr, 'keys'):
         for k, v in list(dict_or_expr.items()):
             dict_or_expr[k] = CompyledFunc(
                 var_names_and_syms=var_names_and_syms, dict_or_expr=v)
         self.Compyled = dict_or_expr
     elif is_non_atomic_sympy_expr(dict_or_expr):
         self.Vars = tuple(
             var for var, symbol in list(var_names_and_syms.items())
             if symbol and not (isinstance(symbol, FLOAT_TYPES)))
         inputs = (var_names_and_syms[var] for var in self.Vars)
         if use_theano:
             self.Compyled = theano_function(inputs, (dict_or_expr, ),
                                             allow_input_downcast=True)
         else:
             self.Compyled = ufuncify(inputs, dict_or_expr)
     else:
         self.Compyled = sympy_to_float(dict_or_expr)
Beispiel #22
0
def build_mixture_loss_and_grad(build_pseudo_functions=False):
    class GaussianPDF(sympy.Function):
        nargs = 3
        is_commutative = False

        @classmethod
        def eval(cls, x, mu, sigma):
            std_x = (x - mu)/sigma    
            return ((
                1/(sigma*sympy.sqrt(sympy.pi*2))
            )*sympy.exp(-(std_x**2)/2))

    class GaussianMixturePDF(sympy.Function):
        nargs = 4

        @classmethod
        def eval(cls, x, mu, sigma, lamda):
            return ( (1-lamda)*GaussianPDF(x, 0, 1) 
                     + lamda*GaussianPDF(x, mu, sigma) )

    class GaussianMixtureCDF(sympy.Function):
        nargs = 4
        
        @classmethod
        def eval(cls, x, mu, sigma, lamda):
            z = sympy.symbols("z", real=True, finite=True)
            rv = sympy.simplify(sympy.Integral(
                    GaussianMixturePDF(z, mu, sigma, lamda), 
                    (z, -sympy.oo, x)).doit())
            return rv
        
    class GaussianMixtureCDF_inverse(sympy.Function):
        """
        @classmethod
        def eval(cls, r, mu, sigma, lamda):
            if mu == 0 and sigma == 1:
                return sympy.erfi(r)
            return sympy.Function('GaussianMixtureCDF_inverse')(
                r, mu, sigma, lamda)
        """
        def _eval_is_real(self):
            return True

        def _eval_is_finite(self):
            return True

        def fdiff(self, argindex):
            r, mu, sigma, lamda = self.args
            # if mu=0 and sigma=1, then this is
            # just the inverse standard erf so return erfi
            if mu == 0 and sigma == 1:
                return sympy.diff(sympy.erfi(r), self.args[argindex-1])

            tmp = sympy.symbols("tmp", real=True, finite=True)
            z_s = GaussianMixtureCDF(tmp, mu, sigma, lamda)
            inv_diff = sympy.diff(z_s, self.args[argindex-1])
            return sympy.simplify(1/inv_diff.subs(tmp, self))            

    # create symbols for the modle params
    lamda_s, sigma_s = sympy.symbols(
        "lamda, sigma", positive=True, real=True, finite=True)
    mu_s, rho_s = sympy.symbols(
        "mu, rho", real=True, finite=True)

    # if we are building the pseudo functiosn then
    # the ranks are what we actually observe, so we need 
    # to wrap them in an inverse CDF call
    if build_pseudo_functions:
        r1_s = sympy.symbols("r1_s", real=True, finite=True, positive=True)
        r2_s = sympy.symbols("r2_s", real=True, finite=True, positive=True)
        z1_s = GaussianMixtureCDF_inverse(r1_s, mu_s, sigma_s, lamda_s)
        z2_s = GaussianMixtureCDF_inverse(r2_s, mu_s, sigma_s, lamda_s)
    # otherwise we just use standard symbols for the obsreved values
    else:
        z1_s, z2_s = sympy.symbols("z1, z2", real=True, finite=True)

    ####### build the marginal densities    
    std_z1_s = (z2_s - mu_s)/sigma_s
    std_z2_s = (z1_s - mu_s)/sigma_s

    ####### bivariate normal density
    sym_signal_density = (
                       1./(2.*sympy.pi*sigma_s*sigma_s)
                      )*(
                       1./sympy.sqrt(1.-rho_s**2)
                      )*sympy.exp(-(
                          std_z1_s**2 + std_z2_s**2 - 2*rho_s*std_z1_s*std_z2_s
                      )/(2*(1-rho_s**2)))

    sym_noise_density = (
                       1./(2.*sympy.pi)
                      )*sympy.exp(-(z1_s**2 + z2_s**2)/2)

    sym_log_lhd = sympy.simplify(sympy.log(lamda_s*sym_signal_density 
                                           + (1-lamda_s)*sym_noise_density))

    # we use the following in the theano calls instead of the z's
    # so that theano won't choke
    pv_1, pv_2 = sympy.symbols('pv_1 pv_2', real=True, finite=True)

    # differentiate, replace the inverse micture CDF's with pv_'s,
    # and then build the theano functions
    sym_gradients = []
    for sym in (mu_s, sigma_s, rho_s, lamda_s):
        sym_grad = sympy.diff(sym_log_lhd, sym)
        pv_sym_grad = sym_grad.subs({z1_s: pv_1, z2_s: pv_2})
        sym_gradients.append( pv_sym_grad )

    theano_gradient = theano_function(
        (mu_s, sigma_s, rho_s, lamda_s, pv_1, pv_2), 
        sym_gradients,
        dims={mu_s:1, sigma_s:1, rho_s:1, lamda_s:1, pv_1: 1, pv_2:1})    

    theano_log_lhd = theano_function(
        (mu_s, sigma_s, rho_s, lamda_s, pv_1, pv_2), 
        [sym_log_lhd.subs({z1_s: pv_1, z2_s: pv_2}),],
        dims={mu_s:1, sigma_s:1, rho_s:1, lamda_s:1, pv_1: 1, pv_2:1})    
        
    # wrap the theano functions in python functions, and return them
    def calc_log_lhd(theta, z1, z2):
        mu, sigma, rho, lamda = theta
        
        return theano_log_lhd(
            numpy.repeat(mu, len(z1)),
            numpy.repeat(sigma, len(z1)),
            numpy.repeat(rho, len(z1)),
            numpy.repeat(lamda, len(z1)),
            z1, z2 ).sum()
    
    def calc_log_lhd_gradient(theta, z1, z2, fix_mu, fix_sigma):
        mu, sigma, rho, lamda = theta

        res = theano_gradient(
            numpy.repeat(mu, len(z1)),
            numpy.repeat(sigma, len(z1)),
            numpy.repeat(rho, len(z1)),
            numpy.repeat(lamda, len(z1)),
            z1, z2 )
        return numpy.array( [x.sum() for x in res] )
    
    return calc_log_lhd, calc_log_lhd_gradient
Beispiel #23
0
from computations.matrices.examples import kalman
from sympy.printing.theanocode import theano_function
f = theano_function(kalman.inputs,
                    kalman.outputs,
                    {i: 'float64' for i in kalman.inputs})
import theano
theano.printing.pydotprint(f, format='dot', outfile='images/theano-kalman')

Beispiel #24
0
def test_bad_keyword_args_raise_error():
    raises(Exception, lambda: theano_function([x], [x + 1], foobar=3))
Beispiel #25
0
def numeric_right_hand_side(mass_matrix, forcing_vector, constants,
                            coordinates, speeds, specified=None,
                            generator='lambdify'):
    """Returns a function for the right hand side of the first order
    ordinary differential equations from a system described by:

    M(constants, coordinates) x' = F(constants, coordinates, speeds, specified)

    which can be evaluated numerically.

    Parameters
    ----------
    mass_matrix : sympy.matrices.dense.MutableDenseMatrix, shape(n,n)
        The symbolic mass matrix of the system.
    forcing_vector : sympy.matrices.dense.MutableDenseMatrix, shape(n,1)
        The symbolic forcing vector of the system.
    constants : list of sympy.core.symbol.Symbol
        The constants in the equations of motion.
    coordinates : list of sympy.core.function.Function
        The generalized coordinates of the system.
    speeds : list of sympy.core.function.Function
        The generalized speeds of the system.
    specified : list of sympy.core.function.Function
        The specifed quantities of the system.
    generator : string, {'lambdify'|'theano'|'cython'}, optional
        The method used for generating the numeric right hand side.

    Returns
    -------
    right_hand_side : function
        A function which evaluates the derivaties of the states.

    """

    if generator == 'lambdify' or generator == 'theano':

        arguments = constants + coordinates + speeds
        if specified is not None:
            arguments += specified

        if generator == 'lambdify':

            mass_matrix_func = lambdify(arguments, mass_matrix)
            forcing_vector_func = lambdify(arguments, forcing_vector)

        elif generator == 'theano':

            mass_matrix_func = theano_function(arguments, [mass_matrix],
                                               on_unused_input='ignore')
            forcing_vector_func = theano_function(arguments,
                                                  [forcing_vector],
                                                  on_unused_input='ignore')
            # Theano will run faster if you trust the input. I'm not sure
            # what the implications of this are. See:
            # http://deeplearning.net/software/theano/tutorial/faq.html#faster-small-theano-function
            mass_matrix_func.trust_input = True
            forcing_vector_func.trust_input = True

        def mass_forcing_func(numerical_constants, numerical_coordinates,
                              numerical_speeds, numerical_specified=None):
            """Returns numerical evaluations of the mass matrix and forcing
            vector."""

            values = [numerical_constants, numerical_coordinates,
                      numerical_speeds]
            if specified is not None:
                values.append(numerical_specified)

            value_array = np.hstack(tuple(values))
            if generator == 'theano':
                value_array = [np.asarray(v) for v in value_array]

            return mass_matrix_func(*value_array), forcing_vector_func(*value_array)

    elif generator == 'cython':

        filename_prefix = 'multibody_system'

        # TODO : This is a hack to allow you to regenerate cython modules
        # without closing the Python session. It may be best to also force
        # the user to provide a module name when generating the Cython code.
        # Check out the Cython inline code to figure out how to do all this
        # better with disutils:
        # https://github.com/cython/cython/blob/master/Cython/Build/Inline.py
        exists = True
        while exists:
            try:
                open(filename_prefix + '.so', 'r')
            except IOError:
                exists = False
            else:
                filename_prefix += '_' + random.choice(all_letters)

        generate_mass_forcing_cython_code(filename_prefix, mass_matrix,
                                          forcing_vector, constants,
                                          coordinates, speeds,
                                          specified=specified)

        cython_module = importlib.import_module(filename_prefix)
        mass_forcing_func = cython_module.mass_forcing_matrices

    else:
        # TODO : add numba, fortan, parakeet, sympy.autowrap (needs matrix
        # support)
        raise NotImplementedError('The {} code generation is not implemented'.format(generator))

    def right_hand_side(x, t, args):
        """Returns the derivatives of the states.

        Parameters
        ----------
        x : ndarray, shape(n,)
            The current state vector.
        t : float
            The current time.
        args : dictionary
            constants : ndarray
            specified : ndarray
            num_coordinates : integer

        Returns
        -------
        dx : ndarray, shape(n,)
            The derivative of the state.

        """
        # TODO : Add more useful info to this doc string. Generate it
        # dynamically.
        # http://stackoverflow.com/questions/10307696/how-to-put-a-variable-into-python-docstring

        # TODO : Allow arg['specified'] to be a function of the states and
        # time, which gets evaluated at each time step.

        segmented = [args['constants'], x[:args['num_coordinates']],
                     x[args['num_coordinates']:]]
        if specified is not None:
            segmented.append(args['specified'])

        mass_matrix_values, forcing_vector_values = \
            mass_forcing_func(*segmented)

        # TODO: figure out how to off load solve to the various generated
        # code, for example for Theano:
        # http://deeplearning.net/software/theano/library/sandbox/linalg.html#theano.sandbox.linalg.ops.Solve

        dx = np.array(np.linalg.solve(mass_matrix_values,
                                      forcing_vector_values)).T[0]

        return dx

    return right_hand_side
Beispiel #26
0
import theano.tensor as T
#from theano import function
from theano import *
from theano.compile import *
from theano.compile.function import *
from sympy.printing.theanocode import theano_function

x = T.dscalar('x')
y = T.dscalar('y')
expr = x + y

#theano.compile.function_dump("a", [x, y], expr)
f = function([x, y], expr)
print f(2,3)

fn_theano = theano_function([x,y], [expr], dims={x: 1, y:1}, dtypes={x: 'float64'})
print fn_theano(2,3)

xx = T.dvector('xx')
yy = T.dvector('yy')
expr_vec = xx + yy
vec_dim = 1
fn_theano_vec = theano_function([xx,yy], [expr_vec]) #, dims={xx: vec_dim, yy: vec_dim}, dtypes={x: 'float64'})
print fn_theano_vec([2,2],[3,3])



NN = 100000

ts = time.time()
for i in range(NN):
Beispiel #27
0
    def __init__(self, model, tspan=None, initials=None, param_values=None,
                 verbose=False, **kwargs):

        super(ScipyOdeSimulator, self).__init__(model,
                                                tspan=tspan,
                                                initials=initials,
                                                param_values=param_values,
                                                verbose=verbose,
                                                **kwargs)
        # We'll need to know if we're using the Jacobian when we get to run()
        self._use_analytic_jacobian = kwargs.get('use_analytic_jacobian',
                                                 False)
        self.cleanup = kwargs.get('cleanup', True)
        integrator = kwargs.get('integrator', 'vode')
        compiler_mode = kwargs.get('compiler', None)
        # Generate the equations for the model
        pysb.bng.generate_equations(self._model, self.cleanup, self.verbose)

        # ODE RHS -----------------------------------------------
        self._eqn_subs = {e: e.expand_expr(expand_observables=True) for
                          e in self._model.expressions}
        ode_mat = sympy.Matrix(self.model.odes).subs(self._eqn_subs)

        if compiler_mode is None:
            self._compiler = self._autoselect_compiler()
            if self._compiler == 'python':
                self._logger.warning(
                    "This system of ODEs will be evaluated in pure Python. "
                    "This may be slow for large models. We recommend "
                    "installing a package for compiling the ODEs to C code: "
                    "'weave' (recommended for Python 2) or "
                    "'cython' (recommended for Python 3). This warning can "
                    "be suppressed by specifying compiler_mode='python'.")
            self._logger.debug('Equation mode set to "%s"' % self._compiler)
        else:
            self._compiler = compiler_mode

        extra_compile_args = []
        # Inhibit weave C compiler warnings unless log level <= EXTENDED_DEBUG.
        # Note that since the output goes straight to stderr rather than via the
        # logging system, the threshold must be lower than DEBUG or else the
        # Nose logcapture plugin will cause the warnings to be shown and tests
        # will fail due to unexpected output.
        if not self._logger.isEnabledFor(EXTENDED_DEBUG):
            extra_compile_args.append('-w')

        # Use lambdarepr (Python code) with Cython, otherwise use C code
        eqn_repr = lambdarepr if self._compiler == 'cython' else sympy.ccode

        if self._compiler in ('weave', 'cython'):
            # Prepare the string representations of the RHS equations

            code_eqs = '\n'.join(['ydot[%d] = %s;' %
                                  (i, eqn_repr(o))
                                  for i, o in enumerate(ode_mat)])
            code_eqs = str(self._eqn_substitutions(code_eqs))

            # Allocate ydot here, once.
            ydot = np.zeros(len(self.model.species))

            if self._compiler == 'cython':
                if not cython:
                    raise ImportError('Cython library is not installed')
                code_eqs = CYTHON_DECL + code_eqs

                def rhs(t, y, p):
                    # note that the evaluated code sets ydot as a side effect
                    cython.inline(code_eqs, quiet=True)

                    return ydot

                with _set_cflags_no_warnings(self._logger):
                    rhs(0.0, self.initials[0], self.param_values[0])
            else:
                # Weave
                if not weave_inline:
                    raise ImportError('Weave library is not installed')
                for arr_name in ('ydot', 'y', 'p'):
                    macro = arr_name.upper() + '1'
                    code_eqs = re.sub(r'\b%s\[(\d+)\]' % arr_name,
                                      '%s(\\1)' % macro, code_eqs)

                def rhs(t, y, p):
                    # note that the evaluated code sets ydot as a side effect
                    weave_inline(code_eqs, ['ydot', 't', 'y', 'p'],
                                 extra_compile_args=extra_compile_args)
                    return ydot

                # Call rhs once just to trigger the weave C compilation step
                # while asserting control over distutils logging.
                with self._patch_distutils_logging:
                    rhs(0.0, self.initials[0], self.param_values[0])

        elif self._compiler in ('theano', 'python'):
            self._symbols = sympy.symbols(','.join('__s%d' % sp_id for sp_id in
                                                   range(len(
                                                       self.model.species)))
                                          + ',') + tuple(model.parameters)

            if self._compiler == 'theano':
                if theano is None:
                    raise ImportError('Theano library is not installed')

                code_eqs_py = theano_function(
                    self._symbols,
                    [o if not o.is_zero else theano.tensor.zeros(1)
                     for o in ode_mat],
                    on_unused_input='ignore'
                )
            else:
                code_eqs_py = sympy.lambdify(self._symbols,
                                             sympy.flatten(ode_mat))

            def rhs(t, y, p):
                return code_eqs_py(*itertools.chain(y, p))
        else:
            raise ValueError('Unknown compiler_mode: %s' % self._compiler)

        # JACOBIAN -----------------------------------------------
        # We'll keep the code for putting together the matrix in Sympy
        # in case we want to do manipulations of the matrix later (e.g., to
        # put together the sensitivity matrix)
        jac_fn = None
        if self._use_analytic_jacobian:
            species_symbols = [sympy.Symbol('__s%d' % i)
                               for i in range(len(self._model.species))]
            jac_matrix = ode_mat.jacobian(species_symbols)

            if self._compiler == 'theano':
                jac_eqs_py = theano_function(
                    self._symbols,
                    [j if not j.is_zero else theano.tensor.zeros(1)
                     for j in jac_matrix],
                    on_unused_input='ignore'
                )

                def jacobian(t, y, p):
                    jacmat = np.asarray(jac_eqs_py(*itertools.chain(y, p)))
                    jacmat.shape = (len(self.model.odes),
                                    len(self.model.species))
                    return jacmat

            elif self._compiler in ('weave', 'cython'):
                # Prepare the stringified Jacobian equations.
                jac_eqs_list = []
                for i in range(jac_matrix.shape[0]):
                    for j in range(jac_matrix.shape[1]):
                        entry = jac_matrix[i, j]
                        # Skip zero entries in the Jacobian
                        if entry == 0:
                            continue
                        jac_eq_str = 'jac[%d, %d] = %s;' % (
                            i, j, eqn_repr(entry))
                        jac_eqs_list.append(jac_eq_str)
                jac_eqs = str(self._eqn_substitutions('\n'.join(jac_eqs_list)))

                # Allocate jac array here, once, and initialize to zeros.
                jac = np.zeros(
                    (len(self._model.odes), len(self._model.species)))

                if self._compiler == 'weave':
                    # Substitute array refs with calls to the JAC1 macro
                    jac_eqs = re.sub(r'\bjac\[(\d+), (\d+)\]',
                                     r'JAC2(\1, \2)', jac_eqs)
                    # Substitute calls to the Y1 and P1 macros
                    for arr_name in ('y', 'p'):
                        macro = arr_name.upper() + '1'
                        jac_eqs = re.sub(r'\b%s\[(\d+)\]' % arr_name,
                                         '%s(\\1)' % macro, jac_eqs)

                    def jacobian(t, y, p):
                        weave_inline(jac_eqs, ['jac', 't', 'y', 'p'],
                                     extra_compile_args=extra_compile_args)
                        return jac

                    # Manage distutils logging, as above for rhs.
                    with self._patch_distutils_logging:
                        jacobian(0.0, self.initials[0], self.param_values[0])
                else:
                    jac_eqs = CYTHON_DECL + jac_eqs

                    def jacobian(t, y, p):
                        cython.inline(jac_eqs, quiet=True)
                        return jac

                    with _set_cflags_no_warnings(self._logger):
                        jacobian(0.0, self.initials[0], self.param_values[0])
            else:
                jac_eqs_py = sympy.lambdify(self._symbols, jac_matrix, "numpy")

                def jacobian(t, y, p):
                    return jac_eqs_py(*itertools.chain(y, p))

            jac_fn = jacobian

        # build integrator options list from our defaults and any kwargs
        # passed to this function
        options = {}
        if self.default_integrator_options.get(integrator):
            options.update(
                self.default_integrator_options[integrator])  # default options

        options.update(kwargs.get('integrator_options', {}))  # overwrite
        # defaults
        self.opts = options

        # Integrator
        if integrator == 'lsoda':
            # lsoda is accessed via scipy.integrate.odeint which,
            # as a function,
            # requires that we pass its args at the point of call. Thus we need
            # to stash stuff like the rhs and jacobian functions in self so we
            # can pass them in later.
            self.integrator = integrator
            # lsoda's rhs and jacobian function arguments are in a different
            # order to other integrators, so we define these shims that swizzle
            # the argument order appropriately.
            self.func = lambda t, y, p: rhs(y, t, p)
            if jac_fn is None:
                self.jac_fn = None
            else:
                self.jac_fn = lambda t, y, p: jac_fn(y, t, p)
        else:
            # The scipy.integrate.ode integrators on the other hand are object
            # oriented and hold the functions and such internally. Once we set
            # up the integrator object we only need to retain a reference to it
            # and can forget about the other bits.
            self.integrator = scipy.integrate.ode(rhs, jac=jac_fn)
            with warnings.catch_warnings():
                warnings.filterwarnings('error', 'No integrator name match')
                self.integrator.set_integrator(integrator, **options)
Beispiel #28
0
                  [1.0 / factorial(j) * x**j for j in range(0, i + 1)])
    f_exprs.append(expr)
    print expr

ts = time.time()
g1 = map(lambda a: function([x], a), f_exprs)
te = time.time()
print g1
print "theano function compile time: ", (te - ts)
print "theano theano_function eval value="
for g in g1:
    print g([0.1])

ts = time.time()
g2 = map(
    lambda a: theano_function([x], [a], dims={x: 1}, dtypes={x: 'float64'}),
    f_exprs)
te = time.time()
print g2
print "sympy.printing.theanocode theano_function compile time: ", (te - ts)
print "sympy.printing.theanocode theano_function eval value="
for g in g2:
    print g([0.1])

nData = 10000  #the best one
NN = 10000000
N = NN / nData
print "Total loops:", N
aryX = [0.1 for i in range(nData)]

for i in range(len(f_exprs)):
Beispiel #29
0
def obs_term_gradient_optimization2(background_data_vector,
                                    observation_data_vector,
                                    actual_B_1,
                                    actual_R_1,
                                    actual_H,
                                    actual_hx,
                                    smallest_gradient=0.01,
                                    iteration_step=0.001,
                                    blockn=5,
                                    enable_parallel=False):
    """http://matthewrocklin.com/blog/work/2013/04/05/SymPy-Theano-part-3"""
    len_background_data_vector = len(background_data_vector)
    len_observation_data_vector = len(background_data_vector)
    # background_error_matrix_reverse = sympy.MatrixSymbol('B_1', len(background_data_vector), len(background_data_vector))
    background_error_matrix_reverse = sympy.MatrixSymbol(
        'B_1', len_background_data_vector, len_background_data_vector)
    observation_error_matrix_reverse = sympy.MatrixSymbol(
        'R_1', len_observation_data_vector, len_observation_data_vector)
    linearized_observation_operator = sympy.MatrixSymbol(
        'H', len_observation_data_vector, len_background_data_vector)
    background_derived_obs_matrix = sympy.MatrixSymbol(
        'hx', len_observation_data_vector, 1)
    observation_data_matrix = sympy.MatrixSymbol('y',
                                                 len_observation_data_vector,
                                                 1)
    analysis_increment_vector_symbol = sympy.MatrixSymbol(
        'delta_x', len_background_data_vector, 1)

    obs_term_gradient_value = numpy.matrix(
        999.0 * numpy.ones(background_data_vector.shape))
    analysis_increment_vector = numpy.matrix(
        numpy.zeros(background_data_vector.shape))

    inputs = [
        background_error_matrix_reverse, observation_error_matrix_reverse,
        linearized_observation_operator, background_derived_obs_matrix,
        observation_data_matrix, analysis_increment_vector_symbol
    ]
    cost_function_gradient = [
        2 * background_error_matrix_reverse * analysis_increment_vector_symbol
        - 2 * linearized_observation_operator.transpose() *
        observation_error_matrix_reverse *
        (observation_data_matrix - background_derived_obs_matrix -
         linearized_observation_operator * analysis_increment_vector_symbol)
    ]

    dtypes = {inp: 'float16' for inp in inputs}

    print 'create func'
    if enable_parallel:
        blocksizes = {
            background_error_matrix_reverse: [
                tuple(blockn * [len_background_data_vector / blockn]),
                tuple(blockn * [len_background_data_vector / blockn])
            ],
            observation_error_matrix_reverse: [
                tuple(blockn * [len_observation_data_vector / blockn]),
                tuple(blockn * [len_observation_data_vector / blockn])
            ],
            linearized_observation_operator: [
                tuple(blockn * [len_observation_data_vector / blockn]),
                tuple(blockn * [len_background_data_vector / blockn])
            ],
            background_derived_obs_matrix:
            [tuple(blockn * [len_observation_data_vector / blockn]), (1, )],
            observation_data_matrix:
            [tuple(blockn * [len_observation_data_vector / blockn]), (1, )],
            analysis_increment_vector_symbol:
            [tuple(blockn * [len_background_data_vector / blockn]), (1, )],
        }
        blockinputs = [blockcut(i, *blocksizes[i]) for i in inputs]
        blockoutputs = [
            o.subs(dict(zip(inputs, blockinputs)))
            for o in cost_function_gradient
        ]
        collapsed_outputs = map(block_collapse, blockoutputs)

        f = theano_function(inputs, collapsed_outputs, dtypes=dtypes)
    else:
        f = theano_function(inputs, cost_function_gradient, dtypes=dtypes)
        #f=sympy.lambdify(analysis_increment_vector_symbol, obs_gradient, 'numpy')
        #f=sympy.lambdify(analysis_increment_vector_symbol, obs_gradient, 'sympy')
    print 'created func'
    n = 0
    while (obs_term_gradient_value.sum() <= -smallest_gradient
           or obs_term_gradient_value.sum() > smallest_gradient):
        ninputs = [
            numpy.array(actual_B_1).astype(float16),
            numpy.array(actual_R_1).astype(float16),
            numpy.array(actual_H).astype(float16),
            numpy.array(actual_hx).astype(float16),
            numpy.array(observation_data_vector).astype(float16),
            numpy.array(analysis_increment_vector).astype(float16)
        ]
        # [2*B_1*delta_x - 2*H.T*R_1*(-hx - H*delta_x + y)]
        # obs_term_gradient_value = 2*actual_B_1*analysis_increment_vector - 2*actual_H.transpose()*actual_R_1*(observation_data_vector-actual_hx-actual_H*analysis_increment_vector)
        #obs_term_gradient_value = 2*numpy.asarray(actual_B_1)*numpy.asarray(analysis_increment_vector) - 2*actual_H.transpose()*actual_R_1*(observation_data_vector-actual_hx-actual_H*analysis_increment_vector)

        obs_term_gradient_value = f(*ninputs)
        analysis_increment_vector = analysis_increment_vector - iteration_step * obs_term_gradient_value

        print n, obs_term_gradient_value.sum()

        n = n + 1

        if n > 2000:
            break

    # print analysis_increment_vector
    # print background_data_vector + analysis_increment_vector
    return background_data_vector + analysis_increment_vector
Beispiel #30
0
def theano_function_(inputs, outputs, **kwargs):
    """ Wrapper for theano_function that uses a new, empty cache by default. """
    kwargs.setdefault('cache', {})
    return theano_function(inputs, outputs, **kwargs)
Beispiel #31
0
def test_bad_keyword_args_raise_error():
    raises(Exception, lambda : theano_function([x], [x+1], foobar=3))
Beispiel #32
0
def generate_ode_function(mass_matrix, forcing_vector, constants,
                          coordinates, speeds, specified=None,
                          generator='lambdify'):
    """Returns a numerical function which can evaluate the right hand side
    of the first order ordinary differential equations from a system
    described by:

    M(constants, coordinates) x' = F(constants, coordinates, speeds, specified)

    Parameters
    ----------
    mass_matrix : sympy.Matrix, shape(n,n)
        The symbolic mass matrix of the system.
    forcing_vector : sympy.Matrix, shape(n,1)
        The symbolic forcing vector of the system.
    constants : list of sympy.Symbol
        The constants in the equations of motion.
    coordinates : list of sympy.Function
        The generalized coordinates of the system.
    speeds : list of sympy.Function
        The generalized speeds of the system.
    specified : list of sympy.Function
        The specifed quantities of the system.
    generator : string, {'lambdify'|'theano'|'cython'}, optional
        The method used for generating the numeric right hand side.

    Returns
    -------
    evaluate_ode_function : function
        A function which evaluates the derivaties of the states.

    """
    if generator == 'theano' and not theano_installed:
        raise ValueError('Theano is not installed.')

    if generator == 'cython' and not cython_installed:
        raise ValueError('Cython is not installed.')

    if generator == 'lambdify' or generator == 'theano':

        arguments = constants + coordinates + speeds
        if specified is not None:
            arguments += specified

        if generator == 'lambdify':

            mass_matrix_func = lambdify(arguments, mass_matrix)
            forcing_vector_func = lambdify(arguments, forcing_vector)

        elif generator == 'theano':

            mass_matrix_func = theano_function(arguments, [mass_matrix],
                                            on_unused_input='ignore')
            forcing_vector_func = theano_function(arguments,
                                                [forcing_vector],
                                                on_unused_input='ignore')
            # Theano will run faster if you trust the input. I'm not sure
            # what the implications of this are. See:
            # http://deeplearning.net/software/theano/tutorial/faq.html#faster-small-theano-function
            mass_matrix_func.trust_input = True
            forcing_vector_func.trust_input = True
        else:
            raise ImportError('Theano is not installed, choose another method.')

        def mass_forcing_func(numerical_constants, numerical_coordinates,
                              numerical_speeds, numerical_specified=None):
            """Returns numerical evaluations of the mass matrix and forcing
            vector."""

            values = [numerical_constants, numerical_coordinates,
                      numerical_speeds]
            if specified is not None:
                values.append(numerical_specified)

            value_array = np.hstack(tuple(values))
            if generator == 'theano':
                value_array = [np.asarray(v) for v in value_array]

            return (mass_matrix_func(*value_array),
                    forcing_vector_func(*value_array))

    elif generator == 'cython':

        filename_prefix = 'multibody_system'

        # TODO : This is a hack to allow you to regenerate cython modules
        # without closing the Python session. It may be best to also force
        # the user to provide a module name when generating the Cython code.
        # Check out the Cython inline code to figure out how to do all this
        # better with disutils:
        # https://github.com/cython/cython/blob/master/Cython/Build/Inline.py

        # The .pyx file has the same prefix as the Cython generated [.dll,
        # .so, .dylib] shared library file, so we should be able to check
        # all files in the directory for matches except the .pyx file.
        prefixes = [os.path.splitext(p)[0] for p in os.listdir('.') if not
                    p.endswith('.pyx')]
        while True:
            if filename_prefix in prefixes:
                filename_prefix += '_' + random.choice(all_letters)
            else:
                break

        cython_generator = CythonGenerator(filename_prefix, mass_matrix,
                                           forcing_vector, constants,
                                           coordinates, speeds,
                                           specified=specified)
        cython_generator.generate_extension()

        cython_module = importlib.import_module(filename_prefix)
        mass_forcing_func = cython_module.mass_forcing_matrices

    else:
        # TODO : add numba, fortran, parakeet, sympy.autowrap (needs matrix
        # support)
        raise NotImplementedError('The {} code generation is not implemented'.format(generator))

    def list_syms(ident, syms):
        identation = ' ' * ident
        return identation + '- ' + ('\n' + identation + '- ').join([str(s) for s in syms])

    def evaluate_ode(x, t, args):
        """Returns the derivatives of the states, i.e. numerically evaluates
        the right hand side of the first order differential equation(s).

        x' = f(x, t)

        Parameters
        ----------
        x : ndarray, shape({num_states},)
            The current state vector:
{state_list}
        t : float
            The current time.
        args : dictionary
            constants : dictionary, len({num_constants})
                A dictionary that maps the constant symbols to floats. The
                dictionary must contain these keys:
{constant_list}
            specified : dictionary; ndarray, shape({num_specified},); function
                There are three options for this dictionary. (1) is more flexible
                but (2) and (3) are much more efficient.
                (1) A dictionary that maps the specified functions of time to
                floats, ndarrays, or functions that produce ndarrays.
                The keys can be a single specified symbolic function of
                time or a tuple of symbols.  The total number of symbols must
                be equal to {num_specified}. If the value is a function it must
                be of the form f(x, t), where x is the current state vector
                ndarray and t is the current time float and it must return an
                ndarray of the correct shape. For example:
                    args['specified'] = {{a: 1.0,
                                         (d, b) : np.array([1.0, 2.0]),
                                         (e, f) : lambda x, t: np.array(x[0], x[1]),
                                         c: lambda x, t: np.array(x[2])}}

                (2) ndarray: The specified values in the same order as the
                symbols given to `generate_ode_function()`, and must be the
                correct shape.
                (3) function: It must be of the form f(x, t), where x is the
                current state vector and t is the current time and it must
                return an ndarray of the correct shape (an ndarray like for
                (2)).

                The dictionary must contain these functions of time:
{specified_list}

        Returns
        -------
        dx : ndarray, shape({num_states},)
            The derivative of the state vector.

        """

        # TODO : It would be nice if the user could pass in empty arrays to
        # be filled instead of creating a new array each time this function
        # is called.

        # TODO : Ideally this dictionary parsing wouldn't be inside this rhs
        # function. Most of it can be moved up on level. This would save
        # computation time.

        segmented = [np.array([args['constants'][c] for c in constants]),
                     x[:len(coordinates)],
                     x[len(coordinates):]]

        if specified is not None:

            if isinstance(args['specified'], dict):

                specified_values = np.zeros(len(specified))

                for k, v in args['specified'].items():
                    # TODO : Not sure if this is the best check here.
                    if isinstance(type(k), UndefinedFunction):
                        k = (k,)
                    idx = [specified.index(symmy) for symmy in k]
                    try:
                        specified_values[idx] = v(x, t)
                    except TypeError:  # not callable
                        # If not callable, then it should be a float, ndarray,
                        # or indexable.
                        specified_values[idx] = v

            else:
                # More efficient.

                try:
                    specified_values = args['specified'](x, t)
                except TypeError: # not callable.
                    # If not callable, then it should be a float or ndarray.
                    specified_values = args['specified']

                # If the value is just a float, then convert to a 1D array.
                try:
                    len(specified_values)
                except TypeError:
                    specified_values = np.asarray([specified_values])

            segmented.append(specified_values)

        mass_matrix_values, forcing_vector_values = \
            mass_forcing_func(*segmented)

        # TODO: figure out how to off load solve to the various generated
        # code, for example for Theano:
        # http://deeplearning.net/software/theano/library/sandbox/linalg.html#theano.sandbox.linalg.ops.Solve

        # Could use scipy.linalg.solve and enable a and b overwriting to
        # avoid the array copying.
        dx = np.array(np.linalg.solve(mass_matrix_values,
                                      forcing_vector_values)).T[0]

        return dx

    template_values = {'num_states': len(coordinates + speeds),
                       'state_list': list_syms(16, coordinates + speeds),
                       'num_constants': len(constants),
                       'constant_list': list_syms(20, constants),
                       'num_specified': '0',
                       'specified_list': '',
                       }

    if specified is not None:
        template_values['num_specified'] = len(specified)
        template_values['specified_list'] = list_syms(20, specified)

    evaluate_ode.__doc__ = evaluate_ode.__doc__.format(**template_values)

    return evaluate_ode
from numpy import array


from sympy.matrices import MatrixSymbol, BlockMatrix, Matrix

x = MatrixSymbol('x', 2, 2)
b = BlockMatrix([[x, x]])

from numpy import array
a = array([[1, 2],
           [3, 4]])

m = BlockMatrix([i for i in range(5)])

o = log(2) + log(3)
f = theano_function([], o)

from frozendict import frozendict


from MathFunc import MathFunc

d0 = MathFunc(dict.fromkeys(('a', 'b')),
             {frozendict(a=1, b=2): 3,
              frozendict(a=10, b=20): 30})

d = MathFunc(dict.fromkeys(('a', 'b')),
             {frozendict(a=1, b=2): 3,
              frozendict(a=10, b=20): 30})
d1 = MathFunc(dict.fromkeys(('b', 'c')),
             {frozendict(c=3, b=2): 30,
Beispiel #34
0
print('+' * 30)
print('Create equations at N(0))')
sy.pprint(C_eq)
print()
#Solve for C_eq
C_sol = sy.solve(C_eq, sy.Symbol('C1'))
soln = ode_sol.subs(sy.Symbol('C1'), C_sol[0])
sy.pprint(C_sol)
sy.pprint(soln)
print('+' * 30)

ode_func = sy.lambdify(t, soln.rhs.subs({N0: 100, r: .2, k: 1000}))
sy.pprint(ode_func(20))
# print('Compare to http://www.ugrad.math.ubc.ca/coursedoc/math100/notes/diffeqs/cool.html')
print()
print('Now use a theano function allowing broadcastable arrays')
from sympy.printing.theanocode import theano_function
theano_ode = theano_function([t], [soln.rhs.subs({
    N0: .15,
    r: .2,
    k: .4
})],
                             dims={t: 1})
tt = np.linspace(0, 80)
theano_output = theano_ode(tt)
sy.pprint(theano_output)
plt.plot(tt, theano_output)
plt.show()
#See http://matthewrocklin.com/blog/work/2013/04/05/SymPy-Theano-part-3
#for better examples on using Theano....
Beispiel #35
0
def numeric_right_hand_side(mass_matrix, forcing_vector, constants,
                            coordinates, speeds, specified=None,
                            generator='lambdify'):
    """Returns a function for the right hand side of the first order
    ordinary differential equations from a system described by:

    M(constants, coordinates) x' = F(constants, coordinates, speeds, specified)

    which can be evaluated numerically.

    Parameters
    ----------
    mass_matrix : sympy.matrices.dense.MutableDenseMatrix, shape(n,n)
        The symbolic mass matrix of the system.
    forcing_vector : sympy.matrices.dense.MutableDenseMatrix, shape(n,1)
        The symbolic forcing vector of the system.
    constants : list of sympy.core.symbol.Symbol
        The constants in the equations of motion.
    coordinates : list of sympy.core.function.Function
        The generalized coordinates of the system.
    speeds : list of sympy.core.function.Function
        The generalized speeds of the system.
    specified : list of sympy.core.function.Function
        The specifed quantities of the system.
    generator : string, {'lambdify'|'theano'|'cython'}, optional
        The method used for generating the numeric right hand side.

    Returns
    -------
    right_hand_side : function
        A function which evaluates the derivaties of the states.

    """

    if generator == 'lambdify' or generator == 'theano':

        arguments = constants + coordinates + speeds
        if specified is not None:
            arguments += specified

        if generator == 'lambdify':

            mass_matrix_func = lambdify(arguments, mass_matrix)
            forcing_vector_func = lambdify(arguments, forcing_vector)

        elif generator == 'theano':

            mass_matrix_func = theano_function(arguments, [mass_matrix],
                                               on_unused_input='ignore')
            forcing_vector_func = theano_function(arguments,
                                                  [forcing_vector],
                                                  on_unused_input='ignore')
            # Theano will run faster if you trust the input. I'm not sure
            # what the implications of this are. See:
            # http://deeplearning.net/software/theano/tutorial/faq.html#faster-small-theano-function
            mass_matrix_func.trust_input = True
            forcing_vector_func.trust_input = True

        def mass_forcing_func(numerical_constants, numerical_coordinates,
                              numerical_speeds, numerical_specified=None):
            """Returns numerical evaluations of the mass matrix and forcing
            vector."""

            values = [numerical_constants, numerical_coordinates,
                      numerical_speeds]
            if specified is not None:
                values.append(numerical_specified)

            value_array = np.hstack(tuple(values))
            if generator == 'theano':
                value_array = [np.asarray(v) for v in value_array]

            return mass_matrix_func(*value_array), forcing_vector_func(*value_array)

    elif generator == 'cython':

        filename_prefix = 'multibody_system'

        # TODO : This is a hack to allow you to regenerate cython modules
        # without closing the Python session. It may be best to also force
        # the user to provide a module name when generating the Cython code.
        # Check out the Cython inline code to figure out how to do all this
        # better with disutils:
        # https://github.com/cython/cython/blob/master/Cython/Build/Inline.py
        exists = True
        while exists:
            try:
                open(filename_prefix + '.so', 'r')
            except IOError:
                exists = False
            else:
                filename_prefix += '_' + random.choice(string.letters)

        generate_mass_forcing_cython_code(filename_prefix, mass_matrix,
                                          forcing_vector, constants,
                                          coordinates, speeds,
                                          specified=specified,
                                          time_variable='t')

        cython_module = importlib.import_module(filename_prefix)
        mass_forcing_func = cython_module.mass_forcing_matrices

    else:
        # TODO : add numba, fortan, parakeet, sympy.autowrap (needs matrix
        # support)
        raise NotImplementedError('The {} code generation is not implemented'.format(generator))

    def right_hand_side(x, t, args):
        """Returns the derivatives of the states.

        Parameters
        ----------
        x : ndarray, shape(n,)
            The current state vector.
        t : float
            The current time.
        args : dictionary
            constants : ndarray
            specified : ndarray
            num_coordinates : integer

        Returns
        -------
        dx : ndarray, shape(n,)
            The derivative of the state.

        """
        # TODO : Add more useful info to this doc string. Generate it
        # dynamically.
        # http://stackoverflow.com/questions/10307696/how-to-put-a-variable-into-python-docstring

        # TODO : Allow arg['specified'] to be a function of the states and
        # time, which gets evaluated at each time step.

        segmented = [args['constants'], x[:args['num_coordinates']],
                     x[args['num_coordinates']:]]
        if specified is not None:
            segmented.append(args['specified'])

        mass_matrix_values, forcing_vector_values = \
            mass_forcing_func(*segmented)

        # TODO: figure out how to off load solve to the various generated
        # code, for example for Theano:
        # http://deeplearning.net/software/theano/library/sandbox/linalg.html#theano.sandbox.linalg.ops.Solve

        dx = np.array(np.linalg.solve(mass_matrix_values,
                                      forcing_vector_values)).T[0]

        return dx

    return right_hand_side
Beispiel #36
0
    def __init__(self,
                 model,
                 tspan=None,
                 initials=None,
                 param_values=None,
                 verbose=False,
                 **kwargs):

        super(ScipyOdeSimulator, self).__init__(model,
                                                tspan=tspan,
                                                initials=initials,
                                                param_values=param_values,
                                                verbose=verbose,
                                                **kwargs)
        # We'll need to know if we're using the Jacobian when we get to run()
        self._use_analytic_jacobian = kwargs.pop('use_analytic_jacobian',
                                                 False)
        self.cleanup = kwargs.pop('cleanup', True)
        integrator = kwargs.pop('integrator', 'vode')
        compiler_mode = kwargs.pop('compiler', None)
        integrator_options = kwargs.pop('integrator_options', {})

        if kwargs:
            raise ValueError('Unknown keyword argument(s): {}'.format(
                ', '.join(kwargs.keys())))
        # Generate the equations for the model
        pysb.bng.generate_equations(self._model, self.cleanup, self.verbose)

        # ODE RHS -----------------------------------------------
        self._eqn_subs = {
            e: e.expand_expr(expand_observables=True)
            for e in self._model.expressions
        }
        self._eqn_subs.update({
            e: e.expand_expr(expand_observables=True)
            for e in self._model._derived_expressions
        })
        ode_mat = sympy.Matrix(self.model.odes).subs(self._eqn_subs)

        if compiler_mode is None:
            self._compiler = self._autoselect_compiler()
            if self._compiler == 'python':
                self._logger.warning(
                    "This system of ODEs will be evaluated in pure Python. "
                    "This may be slow for large models. We recommend "
                    "installing a package for compiling the ODEs to C code: "
                    "'weave' (recommended for Python 2) or "
                    "'cython' (recommended for Python 3). This warning can "
                    "be suppressed by specifying compiler='python'.")
            self._logger.debug('Equation mode set to "%s"' % self._compiler)
        else:
            self._compiler = compiler_mode

        self._compiler_directives = None

        # Use lambdarepr (Python code) with Cython, otherwise use C code
        eqn_repr = lambdarepr if self._compiler == 'cython' else sympy.ccode

        if self._compiler in ('weave', 'cython'):
            # Prepare the string representations of the RHS equations

            code_eqs = '\n'.join([
                'ydot[%d] = %s;' % (i, eqn_repr(o))
                for i, o in enumerate(ode_mat)
            ])
            code_eqs = str(self._eqn_substitutions(code_eqs))

            # Allocate ydot here, once.
            ydot = np.zeros(len(self.model.species))

            if self._compiler == 'cython':
                self._compiler_directives = kwargs.pop(
                    'cython_directives', self.default_cython_directives)

                if not Cython:
                    raise ImportError('Cython library is not installed')

                rhs = _get_rhs(self._compiler,
                               code_eqs,
                               ydot=ydot,
                               compiler_directives=self._compiler_directives)

                with _set_cflags_no_warnings(self._logger):
                    rhs(0.0, self.initials[0], self.param_values[0])
            else:
                # Weave
                self._compiler_directives = []
                # Inhibit weave C compiler warnings unless log
                # level <= EXTENDED_DEBUG. Note that since the output goes
                # straight to stderr rather than via the logging system, the
                # threshold must be lower than DEBUG or else the Nose
                # logcapture plugin will cause the warnings to be shown and
                # tests will fail due to unexpected output.
                if not self._logger.isEnabledFor(EXTENDED_DEBUG):
                    self._compiler_directives.append('-w')
                if not weave_inline:
                    raise ImportError('Weave library is not installed')
                for arr_name in ('ydot', 'y', 'p'):
                    macro = arr_name.upper() + '1'
                    code_eqs = re.sub(r'\b%s\[(\d+)\]' % arr_name,
                                      '%s(\\1)' % macro, code_eqs)

                rhs = _get_rhs(self._compiler,
                               code_eqs,
                               ydot=ydot,
                               compiler_directives=self._compiler_directives)

                # Call rhs once just to trigger the weave C compilation step
                # while asserting control over distutils logging.
                with self._patch_distutils_logging:
                    rhs(0.0, self.initials[0], self.param_values[0])

            self._code_eqs = code_eqs

        elif self._compiler in ('theano', 'python'):
            self._symbols = sympy.symbols(','.join(
                '__s%d' % sp_id
                for sp_id in range(len(self.model.species))) + ',') + tuple(
                    model.parameters)

            if self._compiler == 'theano':
                warnings.warn(
                    "theano backend is deprecated; cython backend is "
                    "recommended instead",
                    category=DeprecationWarning,
                    stacklevel=2)
                if theano is None:
                    raise ImportError('Theano library is not installed')

                code_eqs_py = theano_function(self._symbols, [
                    o if not o.is_zero else theano.tensor.zeros(1)
                    for o in ode_mat
                ],
                                              on_unused_input='ignore')
            else:
                code_eqs_py = sympy.lambdify(self._symbols,
                                             sympy.flatten(ode_mat))

            rhs = _get_rhs(self._compiler, code_eqs_py)
            self._code_eqs = code_eqs_py
        else:
            raise ValueError('Unknown compiler_mode: %s' % self._compiler)

        # JACOBIAN -----------------------------------------------
        # We'll keep the code for putting together the matrix in Sympy
        # in case we want to do manipulations of the matrix later (e.g., to
        # put together the sensitivity matrix)
        jac_fn = None
        self._jac_eqs = None
        if self._use_analytic_jacobian:
            species_symbols = [
                sympy.Symbol('__s%d' % i)
                for i in range(len(self._model.species))
            ]
            jac_matrix = ode_mat.jacobian(species_symbols)

            if self._compiler == 'theano':
                jac_eqs_py = theano_function(self._symbols, [
                    j if not j.is_zero else theano.tensor.zeros(1)
                    for j in jac_matrix
                ],
                                             on_unused_input='ignore')

                def jac_fn(t, y, p):
                    jacmat = np.asarray(jac_eqs_py(*itertools.chain(y, p)))
                    jacmat.shape = (len(self.model.odes),
                                    len(self.model.species))
                    return jacmat

            elif self._compiler in ('weave', 'cython'):
                # Prepare the stringified Jacobian equations.
                jac_eqs_list = []
                for i in range(jac_matrix.shape[0]):
                    for j in range(jac_matrix.shape[1]):
                        entry = jac_matrix[i, j]
                        # Skip zero entries in the Jacobian
                        if entry == 0:
                            continue
                        jac_eq_str = 'jac[%d, %d] = %s;' % (i, j,
                                                            eqn_repr(entry))
                        jac_eqs_list.append(jac_eq_str)
                jac_eqs = str(self._eqn_substitutions('\n'.join(jac_eqs_list)))
                if '# Not supported in Python' in jac_eqs:
                    raise ValueError('Analytic Jacobian calculation failed')

                # Allocate jac array here, once, and initialize to zeros.
                jac = np.zeros(
                    (len(self._model.odes), len(self._model.species)))

                if self._compiler == 'weave':
                    # Substitute array refs with calls to the JAC1 macro
                    jac_eqs = re.sub(r'\bjac\[(\d+), (\d+)\]', r'JAC2(\1, \2)',
                                     jac_eqs)
                    # Substitute calls to the Y1 and P1 macros
                    for arr_name in ('y', 'p'):
                        macro = arr_name.upper() + '1'
                        jac_eqs = re.sub(r'\b%s\[(\d+)\]' % arr_name,
                                         '%s(\\1)' % macro, jac_eqs)

                    jac_fn = _get_rhs(
                        self._compiler,
                        jac_eqs,
                        compiler_directives=self._compiler_directives,
                        jac=jac)

                    # Manage distutils logging, as above for rhs.
                    with self._patch_distutils_logging:
                        jac_fn(0.0, self.initials[0], self.param_values[0])
                else:
                    jac_fn = _get_rhs(
                        self._compiler,
                        jac_eqs,
                        compiler_directives=self._compiler_directives,
                        jac=jac)

                    with _set_cflags_no_warnings(self._logger):
                        jac_fn(0.0, self.initials[0], self.param_values[0])
                self._jac_eqs = jac_eqs
            else:
                jac_eqs_py = sympy.lambdify(self._symbols, jac_matrix, "numpy")

                jac_fn = _get_rhs(self._compiler, jac_eqs_py)

                self._jac_eqs = jac_eqs_py

        # build integrator options list from our defaults and any kwargs
        # passed to this function
        options = {}
        if self.default_integrator_options.get(integrator):
            options.update(
                self.default_integrator_options[integrator])  # default options

        options.update(integrator_options)  # overwrite
        # defaults
        self.opts = options

        if integrator != 'lsoda':
            # Only used to check the user has selected a valid integrator
            self.integrator = scipy.integrate.ode(rhs, jac=jac_fn)
            with warnings.catch_warnings():
                warnings.filterwarnings('error', 'No integrator name match')
                self.integrator.set_integrator(integrator, **options)
Beispiel #37
0
    def __init__(self,
                 model,
                 tspan=None,
                 initials=None,
                 param_values=None,
                 verbose=False,
                 **kwargs):

        super(ScipyOdeSimulator, self).__init__(model,
                                                tspan=tspan,
                                                initials=initials,
                                                param_values=param_values,
                                                verbose=verbose,
                                                **kwargs)
        # We'll need to know if we're using the Jacobian when we get to run()
        self._use_analytic_jacobian = kwargs.get('use_analytic_jacobian',
                                                 False)
        self.cleanup = kwargs.get('cleanup', True)
        integrator = kwargs.get('integrator', 'vode')
        use_theano = kwargs.get('use_theano', False)
        # Generate the equations for the model
        pysb.bng.generate_equations(self._model, self.cleanup, self.verbose)

        # ODE RHS -----------------------------------------------
        self._eqn_subs = {
            e: e.expand_expr(expand_observables=True)
            for e in self._model.expressions
        }
        ode_mat = sympy.Matrix(self.model.odes).subs(self._eqn_subs)

        self._test_inline()

        if self._use_inline:
            # Prepare the string representations of the RHS equations
            code_eqs = '\n'.join([
                'ydot[%d] = %s;' % (i, sympy.ccode(o))
                for i, o in enumerate(ode_mat)
            ])
            code_eqs = self._eqn_substitutions(code_eqs)

            for arr_name in ('ydot', 'y', 'p'):
                macro = arr_name.upper() + '1'
                code_eqs = re.sub(r'\b%s\[(\d+)\]' % arr_name,
                                  '%s(\\1)' % macro, code_eqs)

            def rhs(t, y, p):
                ydot = self.ydot
                # note that the evaluated code sets ydot as a side effect
                weave_inline(code_eqs, ['ydot', 't', 'y', 'p'],
                             extra_compile_args=['-w'])
                return ydot

        if use_theano or not self._use_inline:
            self._symbols = sympy.symbols(','.join(
                '__s%d' % sp_id
                for sp_id in range(len(self.model.species))) + ',') + tuple(
                    model.parameters)

            if use_theano:
                if theano is None:
                    raise ImportError('Theano library is not installed')

                code_eqs_py = theano_function(self._symbols, [
                    o if not o.is_zero else theano.tensor.zeros(1)
                    for o in ode_mat
                ],
                                              on_unused_input='ignore')
            else:
                code_eqs_py = sympy.lambdify(self._symbols,
                                             sympy.flatten(ode_mat))

            def rhs(t, y, p):
                return code_eqs_py(*itertools.chain(y, p))

        # JACOBIAN -----------------------------------------------
        # We'll keep the code for putting together the matrix in Sympy
        # in case we want to do manipulations of the matrix later (e.g., to
        # put together the sensitivity matrix)
        jac_fn = None
        if self._use_analytic_jacobian:
            species_names = [
                '__s%d' % i for i in range(len(self._model.species))
            ]

            jac_matrix = ode_mat.jacobian(species_names)

            if use_theano:
                jac_eqs_py = theano_function(self._symbols, [
                    j if not j.is_zero else theano.tensor.zeros(1)
                    for j in jac_matrix
                ],
                                             on_unused_input='ignore')

                def jacobian(t, y, p):
                    jacmat = np.asarray(jac_eqs_py(*itertools.chain(y, p)))
                    jacmat.shape = (len(self.model.odes),
                                    len(self.model.species))
                    return jacmat

            elif self._use_inline:
                self.jac = np.zeros(
                    (len(self._model.odes), len(self._model.species)))
                # Next, prepare the stringified Jacobian equations
                jac_eqs_list = []
                for i in range(jac_matrix.shape[0]):
                    for j in range(jac_matrix.shape[1]):
                        entry = jac_matrix[i, j]
                        # Skip zero entries in the Jacobian
                        if entry == 0:
                            continue
                        jac_eq_str = 'jac[%d, %d] = %s;' % (i, j,
                                                            sympy.ccode(entry))
                        jac_eqs_list.append(jac_eq_str)
                jac_eqs = self._eqn_substitutions('\n'.join(jac_eqs_list))

                # Substitute array refs with calls to the JAC1 macro for inline
                jac_eqs = re.sub(r'\bjac\[(\d+), (\d+)\]', r'JAC2(\1, \2)',
                                 jac_eqs)
                # Substitute calls to the Y1 and P1 macros
                for arr_name in ('y', 'p'):
                    macro = arr_name.upper() + '1'
                    jac_eqs = re.sub(r'\b%s\[(\d+)\]' % arr_name,
                                     '%s(\\1)' % macro, jac_eqs)

                def jacobian(t, y, p):
                    jac = self.jac
                    weave_inline(jac_eqs, ['jac', 't', 'y', 'p'],
                                 extra_compile_args=['-w'])
                    return jac
            else:
                jac_eqs_py = sympy.lambdify(self._symbols, jac_matrix, "numpy")

                def jacobian(t, y, p):
                    return jac_eqs_py(*itertools.chain(y, p))

            # Initialize the jacobian argument to None if we're not going to
            #  use it
            # jac = self.jac as defined in jacobian() earlier
            # Initialization of matrix for storing the Jacobian
            jac_fn = jacobian

        # build integrator options list from our defaults and any kwargs
        # passed to this function
        options = {}
        if self.default_integrator_options.get(integrator):
            options.update(
                self.default_integrator_options[integrator])  # default options

        options.update(kwargs.get('integrator_options', {}))  # overwrite
        # defaults
        self.opts = options
        self.ydot = np.ndarray(len(self._model.species))

        # Integrator
        if integrator == 'lsoda':
            # lsoda is accessed via scipy.integrate.odeint which,
            # as a function,
            # requires that we pass its args at the point of call. Thus we need
            # to stash stuff like the rhs and jacobian functions in self so we
            # can pass them in later.
            self.integrator = integrator
            # lsoda's rhs and jacobian function arguments are in a different
            # order to other integrators, so we define these shims that swizzle
            # the argument order appropriately.
            self.func = lambda t, y, p: rhs(y, t, p)
            if jac_fn is None:
                self.jac_fn = None
            else:
                self.jac_fn = lambda t, y, p: jac_fn(y, t, p)
        else:
            # The scipy.integrate.ode integrators on the other hand are object
            # oriented and hold the functions and such internally. Once we set
            # up the integrator object we only need to retain a reference to it
            # and can forget about the other bits.
            self.integrator = scipy.integrate.ode(rhs, jac=jac_fn)
            with warnings.catch_warnings():
                warnings.filterwarnings('error', 'No integrator name match')
                self.integrator.set_integrator(integrator, **options)
Beispiel #38
0
def theano_lambdify(args, expr, vector_expr):
    if vector_expr:
        expr_lambda = theano_function(args, expr, on_unused_input='ignore')
    else:
        expr_lambda = theano_function(args, [expr], on_unused_input='ignore')
    return expr_lambda
Beispiel #39
0
def test_theano_function_simple():
    f = theano_function([x, y], [x+y])
    assert f(2, 3) == 5
Beispiel #40
0
def theano_function_(inputs, outputs, **kwargs):
    """ Wrapper for theano_function that uses a new, empty cache by default. """
    kwargs.setdefault('cache', {})
    with warns_deprecated_sympy():
        return theano_function(inputs, outputs, **kwargs)
Beispiel #41
0
def generate_ode_function(mass_matrix, forcing_vector, constants,
                          coordinates, speeds, specified=None,
                          generator='lambdify'):
    """Returns a numerical function which can evaluate the right hand side
    of the first order ordinary differential equations from a system
    described by:

    M(constants, coordinates) x' = F(constants, coordinates, speeds, specified)

    Parameters
    ----------
    mass_matrix : sympy.Matrix, shape(n,n)
        The symbolic mass matrix of the system.
    forcing_vector : sympy.Matrix, shape(n,1)
        The symbolic forcing vector of the system.
    constants : list of sympy.Symbol
        The constants in the equations of motion.
    coordinates : list of sympy.Function
        The generalized coordinates of the system.
    speeds : list of sympy.Function
        The generalized speeds of the system.
    specified : list of sympy.Function
        The specifed quantities of the system.
    generator : string, {'lambdify'|'theano'|'cython'}, optional
        The method used for generating the numeric right hand side.

    Returns
    -------
    evaluate_ode_function : function
        A function which evaluates the derivaties of the states.

    """

    if generator == 'lambdify' or generator == 'theano':

        arguments = constants + coordinates + speeds
        if specified is not None:
            arguments += specified

        if generator == 'lambdify':

            mass_matrix_func = lambdify(arguments, mass_matrix)
            forcing_vector_func = lambdify(arguments, forcing_vector)

        elif generator == 'theano':

            mass_matrix_func = theano_function(arguments, [mass_matrix],
                                               on_unused_input='ignore')
            forcing_vector_func = theano_function(arguments,
                                                  [forcing_vector],
                                                  on_unused_input='ignore')
            # Theano will run faster if you trust the input. I'm not sure
            # what the implications of this are. See:
            # http://deeplearning.net/software/theano/tutorial/faq.html#faster-small-theano-function
            mass_matrix_func.trust_input = True
            forcing_vector_func.trust_input = True

        def mass_forcing_func(numerical_constants, numerical_coordinates,
                              numerical_speeds, numerical_specified=None):
            """Returns numerical evaluations of the mass matrix and forcing
            vector."""

            values = [numerical_constants, numerical_coordinates,
                      numerical_speeds]
            if specified is not None:
                values.append(numerical_specified)

            value_array = np.hstack(tuple(values))
            if generator == 'theano':
                value_array = [np.asarray(v) for v in value_array]

            return (mass_matrix_func(*value_array),
                    forcing_vector_func(*value_array))

    elif generator == 'cython':

        filename_prefix = 'multibody_system'

        # TODO : This is a hack to allow you to regenerate cython modules
        # without closing the Python session. It may be best to also force
        # the user to provide a module name when generating the Cython code.
        # Check out the Cython inline code to figure out how to do all this
        # better with disutils:
        # https://github.com/cython/cython/blob/master/Cython/Build/Inline.py

        # The .pyx file has the same prefix as the Cython generated [.dll,
        # .so, .dylib] shared library file, so we should be able to check
        # all files in the directory for matches except the .pyx file.
        prefixes = [os.path.splitext(p)[0] for p in os.listdir('.') if not
                    p.endswith('.pyx')]
        while True:
            if filename_prefix in prefixes:
                filename_prefix += '_' + random.choice(all_letters)
            else:
                break

        cython_generator = CythonGenerator(filename_prefix, mass_matrix,
                                           forcing_vector, constants,
                                           coordinates, speeds,
                                           specified=specified)
        cython_generator.generate_extension()

        cython_module = importlib.import_module(filename_prefix)
        mass_forcing_func = cython_module.mass_forcing_matrices

    else:
        # TODO : add numba, fortran, parakeet, sympy.autowrap (needs matrix
        # support)
        raise NotImplementedError('The {} code generation is not implemented'.format(generator))

    def evaluate_ode(x, t, args):
        """Returns the derivatives of the states, i.e. numerically evaluates
        the right hand side of the first order differential equation(s).

        x' = f(x, t)

        Parameters
        ----------
        x : ndarray, shape({num_states},)
            The current state vector:
                {state_list}
        t : float
            The current time.
        args : dictionary
            constants : ndarray, shape({num_constants},)
                {constant_list}
            specified : ndarray, shape({num_specified},) or a function
                If this is a function it must be of the form f(x, t), where
                x is the current state vector and t is the current time and
                it must return an ndarray of the correct shape.
                {specified_list}

        Returns
        -------
        dx : ndarray, shape({num_states},)
            The derivative of the state vector.

        """

        segmented = [args['constants'],
                     x[:len(coordinates)],
                     x[len(coordinates):]]

        if specified is not None:
            try:
                sp_val = args['specified'](x, t)
            except TypeError:  # not callable
                # If not callable, then it should be a float or ndarray.
                sp_val = args['specified']

            # If the value is just a float, then convert to a 1D array.
            try:
                len(sp_val)
            except TypeError:
                sp_val = np.asarray([sp_val])

            segmented.append(sp_val)

        mass_matrix_values, forcing_vector_values = \
            mass_forcing_func(*segmented)

        # TODO: figure out how to off load solve to the various generated
        # code, for example for Theano:
        # http://deeplearning.net/software/theano/library/sandbox/linalg.html#theano.sandbox.linalg.ops.Solve

        dx = np.array(np.linalg.solve(mass_matrix_values,
                                      forcing_vector_values)).T[0]

        return dx

    template_values = {'num_states': len(coordinates + speeds),
                       'state_list': ', '.join([str(s) for s in coordinates
                                                + speeds]),
                       'num_constants': len(constants),
                       'constant_list': ', '.join([str(c) for c in constants]),
                       'num_specified': '0',
                       'specified_list': '',
                       }

    if specified is not None:
        template_values['num_specified'] = len(specified)
        template_values['specified_list'] = ', '.join([str(s) for s in
                                                       specified])

    evaluate_ode.__doc__ = evaluate_ode.__doc__.format(**template_values)

    return evaluate_ode
Beispiel #42
0
def test_constantfunctions():
    tf = theano_function([],[1+1j])
    assert(tf()==1+1j)
Beispiel #43
0
def generate_ode_function(mass_matrix,
                          forcing_vector,
                          constants,
                          coordinates,
                          speeds,
                          specified=None,
                          generator='lambdify'):
    """Returns a numerical function which can evaluate the right hand side
    of the first order ordinary differential equations from a system
    described by:

    M(constants, coordinates) x' = F(constants, coordinates, speeds, specified)

    Parameters
    ----------
    mass_matrix : sympy.Matrix, shape(n,n)
        The symbolic mass matrix of the system.
    forcing_vector : sympy.Matrix, shape(n,1)
        The symbolic forcing vector of the system.
    constants : list of sympy.Symbol
        The constants in the equations of motion.
    coordinates : list of sympy.Function
        The generalized coordinates of the system.
    speeds : list of sympy.Function
        The generalized speeds of the system.
    specified : list of sympy.Function
        The specifed quantities of the system.
    generator : string, {'lambdify'|'theano'|'cython'}, optional
        The method used for generating the numeric right hand side.

    Returns
    -------
    evaluate_ode_function : function
        A function which evaluates the derivaties of the states.

    """
    if generator == 'theano' and not theano_installed:
        raise ValueError('Theano is not installed.')

    if generator == 'cython' and not cython_installed:
        raise ValueError('Cython is not installed.')

    if generator == 'lambdify' or generator == 'theano':

        arguments = constants + coordinates + speeds
        if specified is not None:
            arguments += specified

        if generator == 'lambdify':

            mass_matrix_func = lambdify(arguments, mass_matrix)
            forcing_vector_func = lambdify(arguments, forcing_vector)

        elif generator == 'theano':

            mass_matrix_func = theano_function(arguments, [mass_matrix],
                                               on_unused_input='ignore')
            forcing_vector_func = theano_function(arguments, [forcing_vector],
                                                  on_unused_input='ignore')
            # Theano will run faster if you trust the input. I'm not sure
            # what the implications of this are. See:
            # http://deeplearning.net/software/theano/tutorial/faq.html#faster-small-theano-function
            mass_matrix_func.trust_input = True
            forcing_vector_func.trust_input = True
        else:
            raise ImportError(
                'Theano is not installed, choose another method.')

        def mass_forcing_func(numerical_constants,
                              numerical_coordinates,
                              numerical_speeds,
                              numerical_specified=None):
            """Returns numerical evaluations of the mass matrix and forcing
            vector."""

            values = [
                numerical_constants, numerical_coordinates, numerical_speeds
            ]
            if specified is not None:
                values.append(numerical_specified)

            value_array = np.hstack(tuple(values))
            if generator == 'theano':
                value_array = [np.asarray(v) for v in value_array]

            return (mass_matrix_func(*value_array),
                    forcing_vector_func(*value_array))

    elif generator == 'cython':

        filename_prefix = 'multibody_system'

        # TODO : This is a hack to allow you to regenerate cython modules
        # without closing the Python session. It may be best to also force
        # the user to provide a module name when generating the Cython code.
        # Check out the Cython inline code to figure out how to do all this
        # better with disutils:
        # https://github.com/cython/cython/blob/master/Cython/Build/Inline.py

        # The .pyx file has the same prefix as the Cython generated [.dll,
        # .so, .dylib] shared library file, so we should be able to check
        # all files in the directory for matches except the .pyx file.
        prefixes = [
            os.path.splitext(p)[0] for p in os.listdir('.')
            if not p.endswith('.pyx')
        ]
        while True:
            if filename_prefix in prefixes:
                filename_prefix += '_' + random.choice(all_letters)
            else:
                break

        cython_generator = CythonGenerator(filename_prefix,
                                           mass_matrix,
                                           forcing_vector,
                                           constants,
                                           coordinates,
                                           speeds,
                                           specified=specified)
        cython_generator.generate_extension()

        cython_module = importlib.import_module(filename_prefix)
        mass_forcing_func = cython_module.mass_forcing_matrices

    else:
        # TODO : add numba, fortran, parakeet, sympy.autowrap (needs matrix
        # support)
        raise NotImplementedError(
            'The {} code generation is not implemented'.format(generator))

    def evaluate_ode(x, t, args):
        """Returns the derivatives of the states, i.e. numerically evaluates
        the right hand side of the first order differential equation(s).

        x' = f(x, t)

        Parameters
        ----------
        x : ndarray, shape({num_states},)
            The current state vector:
                {state_list}
        t : float
            The current time.
        args : dictionary
            constants : ndarray, shape({num_constants},)
                {constant_list}
            specified : ndarray, shape({num_specified},) or a function
                If this is a function it must be of the form f(x, t), where
                x is the current state vector and t is the current time and
                it must return an ndarray of the correct shape.
                {specified_list}

        Returns
        -------
        dx : ndarray, shape({num_states},)
            The derivative of the state vector.

        """

        segmented = [
            args['constants'], x[:len(coordinates)], x[len(coordinates):]
        ]

        if specified is not None:
            try:
                sp_val = args['specified'](x, t)
            except TypeError:  # not callable
                # If not callable, then it should be a float or ndarray.
                sp_val = args['specified']

            # If the value is just a float, then convert to a 1D array.
            try:
                len(sp_val)
            except TypeError:
                sp_val = np.asarray([sp_val])

            segmented.append(sp_val)

        mass_matrix_values, forcing_vector_values = \
            mass_forcing_func(*segmented)

        # TODO: figure out how to off load solve to the various generated
        # code, for example for Theano:
        # http://deeplearning.net/software/theano/library/sandbox/linalg.html#theano.sandbox.linalg.ops.Solve

        # Could use scipy.linalg.solve and enable a and b overwriting to
        # avoid the array copying.
        dx = np.array(
            np.linalg.solve(mass_matrix_values, forcing_vector_values)).T[0]

        return dx

    template_values = {
        'num_states': len(coordinates + speeds),
        'state_list': ', '.join([str(s) for s in coordinates + speeds]),
        'num_constants': len(constants),
        'constant_list': ', '.join([str(c) for c in constants]),
        'num_specified': '0',
        'specified_list': '',
    }

    if specified is not None:
        template_values['num_specified'] = len(specified)
        template_values['specified_list'] = ', '.join(
            [str(s) for s in specified])

    evaluate_ode.__doc__ = evaluate_ode.__doc__.format(**template_values)

    return evaluate_ode
Beispiel #44
0
    def __init__(self, model, tspan=None, initials=None, param_values=None,
                 verbose=False, **kwargs):

        super(ScipyOdeSimulator, self).__init__(model,
                                                tspan=tspan,
                                                initials=initials,
                                                param_values=param_values,
                                                verbose=verbose,
                                                **kwargs)
        # We'll need to know if we're using the Jacobian when we get to run()
        self._use_analytic_jacobian = kwargs.pop('use_analytic_jacobian',
                                                 False)
        self.cleanup = kwargs.pop('cleanup', True)
        integrator = kwargs.pop('integrator', 'vode')
        compiler_mode = kwargs.pop('compiler', None)
        integrator_options = kwargs.pop('integrator_options', {})
        cython_directives = kwargs.pop('cython_directives',
                                       self.default_cython_directives)
        if kwargs:
            raise ValueError('Unknown keyword argument(s): {}'.format(
                ', '.join(kwargs.keys())
            ))
        # Generate the equations for the model
        pysb.bng.generate_equations(self._model, self.cleanup, self.verbose)

        # ODE RHS -----------------------------------------------
        self._eqn_subs = {e: e.expand_expr(expand_observables=True) for
                          e in self._model.expressions}
        ode_mat = sympy.Matrix(self.model.odes).subs(self._eqn_subs)

        if compiler_mode is None:
            self._compiler = self._autoselect_compiler()
            if self._compiler == 'python':
                self._logger.warning(
                    "This system of ODEs will be evaluated in pure Python. "
                    "This may be slow for large models. We recommend "
                    "installing a package for compiling the ODEs to C code: "
                    "'weave' (recommended for Python 2) or "
                    "'cython' (recommended for Python 3). This warning can "
                    "be suppressed by specifying compiler='python'.")
            self._logger.debug('Equation mode set to "%s"' % self._compiler)
        else:
            self._compiler = compiler_mode

        extra_compile_args = []
        # Inhibit weave C compiler warnings unless log level <= EXTENDED_DEBUG.
        # Note that since the output goes straight to stderr rather than via the
        # logging system, the threshold must be lower than DEBUG or else the
        # Nose logcapture plugin will cause the warnings to be shown and tests
        # will fail due to unexpected output.
        if not self._logger.isEnabledFor(EXTENDED_DEBUG):
            extra_compile_args.append('-w')

        # Use lambdarepr (Python code) with Cython, otherwise use C code
        eqn_repr = lambdarepr if self._compiler == 'cython' else sympy.ccode

        if self._compiler in ('weave', 'cython'):
            # Prepare the string representations of the RHS equations

            code_eqs = '\n'.join(['ydot[%d] = %s;' %
                                  (i, eqn_repr(o))
                                  for i, o in enumerate(ode_mat)])
            code_eqs = str(self._eqn_substitutions(code_eqs))

            # Allocate ydot here, once.
            ydot = np.zeros(len(self.model.species))

            if self._compiler == 'cython':
                if not Cython:
                    raise ImportError('Cython library is not installed')

                def rhs(t, y, p):
                    # note that the evaluated code sets ydot as a side effect
                    Cython.inline(
                        code_eqs, quiet=True,
                        cython_compiler_directives=cython_directives)

                    return ydot

                with _set_cflags_no_warnings(self._logger):
                    rhs(0.0, self.initials[0], self.param_values[0])
            else:
                # Weave
                if not weave_inline:
                    raise ImportError('Weave library is not installed')
                for arr_name in ('ydot', 'y', 'p'):
                    macro = arr_name.upper() + '1'
                    code_eqs = re.sub(r'\b%s\[(\d+)\]' % arr_name,
                                      '%s(\\1)' % macro, code_eqs)

                def rhs(t, y, p):
                    # note that the evaluated code sets ydot as a side effect
                    weave_inline(code_eqs, ['ydot', 't', 'y', 'p'],
                                 extra_compile_args=extra_compile_args)
                    return ydot

                # Call rhs once just to trigger the weave C compilation step
                # while asserting control over distutils logging.
                with self._patch_distutils_logging:
                    rhs(0.0, self.initials[0], self.param_values[0])

        elif self._compiler in ('theano', 'python'):
            self._symbols = sympy.symbols(','.join('__s%d' % sp_id for sp_id in
                                                   range(len(
                                                       self.model.species)))
                                          + ',') + tuple(model.parameters)

            if self._compiler == 'theano':
                if theano is None:
                    raise ImportError('Theano library is not installed')

                code_eqs_py = theano_function(
                    self._symbols,
                    [o if not o.is_zero else theano.tensor.zeros(1)
                     for o in ode_mat],
                    on_unused_input='ignore'
                )
            else:
                code_eqs_py = sympy.lambdify(self._symbols,
                                             sympy.flatten(ode_mat))

            def rhs(t, y, p):
                return code_eqs_py(*itertools.chain(y, p))
        else:
            raise ValueError('Unknown compiler_mode: %s' % self._compiler)

        # JACOBIAN -----------------------------------------------
        # We'll keep the code for putting together the matrix in Sympy
        # in case we want to do manipulations of the matrix later (e.g., to
        # put together the sensitivity matrix)
        jac_fn = None
        if self._use_analytic_jacobian:
            species_symbols = [sympy.Symbol('__s%d' % i)
                               for i in range(len(self._model.species))]
            jac_matrix = ode_mat.jacobian(species_symbols)

            if self._compiler == 'theano':
                jac_eqs_py = theano_function(
                    self._symbols,
                    [j if not j.is_zero else theano.tensor.zeros(1)
                     for j in jac_matrix],
                    on_unused_input='ignore'
                )

                def jacobian(t, y, p):
                    jacmat = np.asarray(jac_eqs_py(*itertools.chain(y, p)))
                    jacmat.shape = (len(self.model.odes),
                                    len(self.model.species))
                    return jacmat

            elif self._compiler in ('weave', 'cython'):
                # Prepare the stringified Jacobian equations.
                jac_eqs_list = []
                for i in range(jac_matrix.shape[0]):
                    for j in range(jac_matrix.shape[1]):
                        entry = jac_matrix[i, j]
                        # Skip zero entries in the Jacobian
                        if entry == 0:
                            continue
                        jac_eq_str = 'jac[%d, %d] = %s;' % (
                            i, j, eqn_repr(entry))
                        jac_eqs_list.append(jac_eq_str)
                jac_eqs = str(self._eqn_substitutions('\n'.join(jac_eqs_list)))

                # Allocate jac array here, once, and initialize to zeros.
                jac = np.zeros(
                    (len(self._model.odes), len(self._model.species)))

                if self._compiler == 'weave':
                    # Substitute array refs with calls to the JAC1 macro
                    jac_eqs = re.sub(r'\bjac\[(\d+), (\d+)\]',
                                     r'JAC2(\1, \2)', jac_eqs)
                    # Substitute calls to the Y1 and P1 macros
                    for arr_name in ('y', 'p'):
                        macro = arr_name.upper() + '1'
                        jac_eqs = re.sub(r'\b%s\[(\d+)\]' % arr_name,
                                         '%s(\\1)' % macro, jac_eqs)

                    def jacobian(t, y, p):
                        weave_inline(jac_eqs, ['jac', 't', 'y', 'p'],
                                     extra_compile_args=extra_compile_args)
                        return jac

                    # Manage distutils logging, as above for rhs.
                    with self._patch_distutils_logging:
                        jacobian(0.0, self.initials[0], self.param_values[0])
                else:
                    def jacobian(t, y, p):
                        Cython.inline(
                            jac_eqs, quiet=True,
                            cython_compiler_directives=cython_directives)
                        return jac

                    with _set_cflags_no_warnings(self._logger):
                        jacobian(0.0, self.initials[0], self.param_values[0])
            else:
                jac_eqs_py = sympy.lambdify(self._symbols, jac_matrix, "numpy")

                def jacobian(t, y, p):
                    return jac_eqs_py(*itertools.chain(y, p))

            jac_fn = jacobian

        # build integrator options list from our defaults and any kwargs
        # passed to this function
        options = {}
        if self.default_integrator_options.get(integrator):
            options.update(
                self.default_integrator_options[integrator])  # default options

        options.update(integrator_options)  # overwrite
        # defaults
        self.opts = options

        # Integrator
        if integrator == 'lsoda':
            # lsoda is accessed via scipy.integrate.odeint which,
            # as a function,
            # requires that we pass its args at the point of call. Thus we need
            # to stash stuff like the rhs and jacobian functions in self so we
            # can pass them in later.
            self.integrator = integrator
            # lsoda's rhs and jacobian function arguments are in a different
            # order to other integrators, so we define these shims that swizzle
            # the argument order appropriately.
            self.func = lambda t, y, p: rhs(y, t, p)
            if jac_fn is None:
                self.jac_fn = None
            else:
                self.jac_fn = lambda t, y, p: jac_fn(y, t, p)
        else:
            # The scipy.integrate.ode integrators on the other hand are object
            # oriented and hold the functions and such internally. Once we set
            # up the integrator object we only need to retain a reference to it
            # and can forget about the other bits.
            self.integrator = scipy.integrate.ode(rhs, jac=jac_fn)
            with warnings.catch_warnings():
                warnings.filterwarnings('error', 'No integrator name match')
                self.integrator.set_integrator(integrator, **options)
Beispiel #45
0
def cython_propensity_function(x, parm, prop):
    args = x + parm.keys()
    return (theano_function(args, prop), args)
Beispiel #46
0
def test_constantfunctions():
    tf = theano_function([], [1 + 1j])
    assert (tf() == 1 + 1j)
Beispiel #47
0
    def __init__(self,
                 venture_name='',
                 year_0=0,
                 nb_pro_forma_years_excl_0=1,
                 compile=True):

        # set Venture Name and corresponding variable prefixes
        self.venture_name = venture_name
        if venture_name:
            self.venture_name_prefix = '%s___' % venture_name
        else:
            self.venture_name_prefix = ''

        # set pro forma period timeline
        self.year_0 = year_0
        self.nb_pro_forma_years_excl_0 = nb_pro_forma_years_excl_0
        self.nb_pro_forma_years_incl_0 = nb_pro_forma_years_excl_0 + 1
        self.final_pro_forma_year = year_0 + nb_pro_forma_years_excl_0
        self.index_range = range(self.nb_pro_forma_years_incl_0)
        self.index_range_from_1 = range(1, self.nb_pro_forma_years_incl_0)

        # list all Input & Output attributes & symbols, and set model structure
        self.input_attrs = []
        self.output_attrs = []
        self.set_model_structure()

        # gather all Input symbols and set their default values
        self.input_symbols = []
        self.input_defaults = {}
        for input_attr in self.input_attrs:
            a = getattr(self, '%s___input' % input_attr)
            if isinstance(a, (list, tuple)):
                if (not isinstance(a[0], Symbol)) and isnan(a[0]):
                    for i in self.index_range_from_1:
                        self.input_symbols.append(a[i])
                        self.input_defaults[a[i].name] = -1.
                else:
                    for i in self.index_range:
                        self.input_symbols.append(a[i])
                        self.input_defaults[a[i].name] = 0.
            else:
                self.input_symbols.append(a)
                self.input_defaults[a.name] = 0.

        # compile Outputs if so required
        self.compile = compile
        if compile:

            def format_time_delta(time_delta):
                time_delta_str = str(time_delta)
                return time_delta_str[:time_delta_str.index('.')]

            print('Compiling:')
            tic_0 = datetime.now()
            for output in self.output_attrs:
                print('    %s... ' % output, end='')
                a = getattr(self, output)
                tic = datetime.now()
                if isinstance(a, (list, tuple)):
                    if (not isinstance(a[0], Expr)) and isnan(a[0]):
                        setattr(self, output, [nan] + [
                            theano_function(self.input_symbols, [a[i]])
                            for i in self.index_range_from_1
                        ])
                    else:
                        setattr(self, output, [
                            theano_function(self.input_symbols, [a[i]])
                            for i in self.index_range
                        ])
                else:
                    setattr(self, output,
                            theano_function(self.input_symbols, [a]))
                toc = datetime.now()
                print('done after %s (%s so far)' %
                      (format_time_delta(toc - tic),
                       format_time_delta(toc - tic_0)))
            print('done after %s' % format_time_delta(toc - tic_0))
Beispiel #48
0
def theano_function_(inputs, outputs, **kwargs):
    """ Wrapper for theano_function that uses a new, empty cache by default. """
    kwargs.setdefault('cache', {})
    return theano_function(inputs, outputs, **kwargs)