Продукт Theano Dot - PullRequest
       9

Продукт Theano Dot

0 голосов
/ 06 января 2019

Ниже приведен код для решения уравнения теплопроводности / диффузии с периодическими граничными условиями. Таким образом, при вычислении производной функции на каждом шаге РК мне нужно сделать скалярное произведение между входным вектором и матрицей Теплица. Это происходит правильно для первой итерации (проверено с результатами scipy.integrate), а для второй и далее что-то идет не так, и решение взрывается. Я не могу понять, в чем проблема. Пожалуйста помоги. Код является модификацией https://gist.github.com/michaelosthege/a75b565d3f653721fa235a07eb089912.

import abc
import theano.tensor as tt
import theano
import numpy as np
from scipy.linalg import inv, toeplitz

#################################### Integrator class #############################

class Integrator(object):
    __metaclass__ = abc.ABCMeta
    def step(self, t, dt, y, dydt, theta):
        raise NotImplementedError()

class TheanoIntegrationOps(object):
    def __init__(self, dydt_theano, integrator:Integrator):
        self.dydt_theano = dydt_theano
        self.integrator = integrator
        return super().__init__()

    def __step_theano(self, t, y_t, dt_t, nrk4steps, t_theta):
        return self.integrator.step(t, dt_t, y_t, self.dydt_theano, 
                    nrk4steps, t_theta)

    def __call__(self, y0, theta, times, nrk4steps):
        t_y0 = tt.as_tensor_variable(y0)
        t_theta = tt.as_tensor_variable(theta)
        t_times = tt.as_tensor_variable(times)
        dt = (times[1] - times[0])/nrk4steps

        Y_hat, updates = theano.scan(fn=self.__step_theano,
                                    outputs_info =[{'initial':t_y0}],
                                    sequences=[t_times],
                                    non_sequences=[dt, nrk4steps, t_theta],
                                    n_steps=len(times)-1)

        Y_hat = tt.concatenate((t_y0[None,:], Y_hat))
        Y_hat = tt.transpose(Y_hat)
        return Y_hat

# Simple RK integrator

class RungeKutta(Integrator):
    def step(self, t, dt, y, dydt, nrk4steps, theta):
        for i in range(nrk4steps.eval()):
            k1 = dt*dydt(y, t, theta)
            k2 = dt*dydt(y + 0.5*k1, t, theta)
            k3 = dt*dydt(y + 0.5*k2, t, theta)
            k4 = dt*dydt(y + k3, t, theta)
            y = y + (1./6.)*k1 + (1./3.)*k2 + (1./3.)*k3 + (1./6.)*k4
        return y


#################################################################

# The derivative function for heat equation
def dydt(c, t, theta):
    nx = 128
    gridx = np.arange(0.0, 1, 1.0/nx)
    dx = gridx[1] - gridx[0]
    z = np.zeros_like(gridx)
    z[0] = -2
    z[1] =  1 
    z[-1] = 1
    diff = 2
    diff_matrix = toeplitz(z) / dx**2
    diff_matrix = tt.as_tensor_variable(diff_matrix)
    dc_dt = tt.zeros_like(c)
    # This is what causes the problem
    dc_dt = theano.dot(c, diff_matrix)
    return dc_dt

if __name__=="__main__":
    # Number of RK4 iterations between each time point
    nrk4steps = 1
    # Time points
    times=np.linspace(0,1,101)
    # Initial Condition
    nx = 128
    gridx = np.arange(0.0, 1, 1.0/nx)
    T_y0 = np.sin(2*np.pi*gridx)
    # Diffusion constant
    T_theta = [2.0,]
    integrator = RungeKutta()
    Y_hat_TV = TheanoIntegrationOps(dydt, integrator)(
                T_y0, T_theta, times, nrk4steps)
    Ysim = np.transpose(Y_hat_TV.eval())
    print(Ysim)
~
...