Пример #1
0
def trapezoidal_rule(f, dt=None, epsilon=1e-12):
    """Trapezoidal rule.

    The trapezoidal rule is an implicit second-order method, which can
    be considered as both a Runge–Kutta method and a linear multistep method.

    Parameters
    ----------
    f : callable
        The function at the right hand of the differential equation.
    dt : None, float
        Precision of numerical integration.

    Returns
    -------
    func : callable
        The one-step numerical integration function.
    """
    f = autojit(f)
    if dt is None:
        dt = profile.get_dt()

    def int_f(y0, t, *args):
        dy0 = f(y0, t, *args)
        y1 = y0 + dt * dy0
        y2 = y0 + dt / 2 * (dy0 + f(y1, t + dt, *args))
        while not np.all(np.abs(y1 - y2) < epsilon):
            y1 = y2
            y2 = y0 + dt / 2 * (dy0 + f(y1, t + dt, *args))
        return y2

    return autojit(int_f)
Пример #2
0
def backward_Euler(f, dt=None, epsilon=1e-12):
    """Backward Euler method. Also named as ``implicit_Euler``.

    Parameters
    ----------
    f : callable
        The function at the right hand of the differential equation.
    dt : None, float
        Precision of numerical integration.

    Returns
    -------
    func : callable
        The one-step numerical integration function.
    """
    f = autojit(f)
    if dt is None:
        dt = profile.get_dt()

    def int_f(y0, t, *args):
        y1 = y0 + dt * f(y0, t, *args)
        y2 = y0 + dt * f(y1, t, *args)
        while not np.all(np.abs(y1 - y2) < epsilon):
            y1 = y2
            y2 = y0 + dt * f(y1, t, *args)
        return y2

    return autojit(int_f)
Пример #3
0
def rk4_alternative(f, dt=None):
    """An alternative of fourth-order Runge-Kutta method.
    Also named as ``RK4_alternative``.

    Parameters
    ----------
    f : callable
        The function at the right hand of the differential equation.
    dt : None, float
        Precision of numerical integration.

    Returns
    -------
    func : callable
        The one-step numerical integration function.
    """
    f = autojit(f)
    if dt is None:
        dt = profile.get_dt()

    def int_f(y0, t, *args):
        k1 = f(y0, t, *args)
        k2 = f(y0 + dt / 3 * k1, t + dt / 3, *args)
        k3 = f(y0 - dt / 3 * k1 + dt * k2, t + 2 * dt / 3, *args)
        k4 = f(y0 + dt * k1 - dt * k2 + dt * k3, t + dt, *args)
        return y0 + dt / 8 * (k1 + 3 * k2 + 3 * k3 + k4)

    return autojit(int_f)
Пример #4
0
def rk3(f, dt=None):
    """Kutta's third-order method (commonly known as RK3).
    Also named as ``RK3``.

    Parameters
    ----------
    f : callable
        The function at the right hand of the differential equation.
    dt : None, float
        Precision of numerical integration.

    Returns
    -------
    func : callable
        The one-step numerical integration function.
    """
    f = autojit(f)
    if dt is None:
        dt = profile.get_dt()

    def int_f(y0, t, *args):
        k1 = f(y0, t, *args)
        k2 = f(y0 + dt / 2 * k1, t + dt / 2, *args)
        k3 = f(y0 - dt * k1 + 2 * dt * k2, t + dt, *args)
        return y0 + dt / 6 * (k1 + 4 * k2 + k3)

    return autojit(int_f)
Пример #5
0
def rk2(f, dt=None, beta=2 / 3):
    """Parametric second-order Runge-Kutta (RK2).
    Also named as ``RK2``.

    Popular choices for 'beta':
        1/2 :
            explicit midpoint method
        2/3 :
            Ralston's method
        1 :
            Heun's method, also known as the explicit trapezoid rule

    Parameters
    ----------
    f : callable
        The function at the right hand of the differential equation.
    dt : None, float
        Precision of numerical integration.

    Returns
    -------
    func : callable
        The one-step numerical integration function.
    """
    f = autojit(f)
    if dt is None:
        dt = profile.get_dt()

    def int_f(y0, t, *args):
        k1 = f(y0, t, *args)
        k2 = f(y0 + beta * dt * k1, t + beta * dt, *args)
        return y0 + dt * ((1 - 1 / (2 * beta)) * k1 + 1 / (2 * beta) * k2)

    return autojit(int_f)
Пример #6
0
def forward_Euler(f, dt=None):
    """Forward Euler method. Also named as ``explicit_Euler``.

    The most unstable integrator known. Requires a very small timestep.
    Accuracy is O(dt).

    Parameters
    ----------
    f : callable
        The function at the right hand of the differential equation.
    dt : None, float
        Precision of numerical integration.

    Returns
    -------
    func : callable
        The one-step numerical integration function.
    """
    f = autojit(f)
    if dt is None:
        dt = profile.get_dt()

    def int_f(y0, t, *args):
        return y0 + dt * f(y0, t, *args)

    return autojit(int_f)
Пример #7
0
def Heun_method(f, g, dt=None):
    """Stratonovich stochastic integral.

    Use the Stratonovich Heun algorithm
    to integrate Stratonovich equation,
    according to paper [2]_, [3]_.

    Parameters
    ----------
    f : callable
        The drift coefficient, the deterministic part of the SDE.
    g : callable, float
        The diffusion coefficient, the stochastic part.
    dt : None, float
        Precision of numerical integration.

    Returns
    -------
    func : callable
        The one-step numerical integration function.

    References
    ----------

    .. [2] H. Gilsing and T. Shardlow, SDELab: A package for solving stochastic differential
         equations in MATLAB, Journal of Computational and Applied Mathematics 205 (2007),
         no. 2, 1002{1018.
    .. [3] P.E. Kloeden, E. Platen, and H. Schurz, Numerical solution of SDE through computer
         experiments, Springer, 1994.
    """
    dt = profile.get_dt() if dt is None else dt
    dt_sqrt = np.sqrt(dt)
    f = autojit(f)

    if callable(g):
        g = autojit(g)

        def int_fg(y0, t, *args):
            dW = np.random.normal(0.0, 1.0, y0.shape)
            df = f(y0, t - dt, *args) * dt
            gn = g(y0, t - dt, *args)
            y_bar = y0 + gn * dW * dt_sqrt
            gn_bar = g(y_bar, t, *args)
            dg = 0.5 * (gn + gn_bar) * dW * dt_sqrt
            y1 = y0 + df + dg
            return y1
    else:
        assert isinstance(g, (int, float, np.ndarray))

        def int_fg(y0, t, *args):
            dW = np.random.normal(0.0, 1.0, y0.shape)
            df = f(y0, t - dt, *args) * dt
            dg = g * dW * dt_sqrt
            y1 = y0 + df + dg
            return y1

    return autojit(int_fg)
Пример #8
0
def Milstein_dfree_Stra(f, g, dt=None):
    """Stratonovich stochastic integral. The derivative-free Milstein
    method is an order 1.0 strong Taylor schema.

    Parameters
    ----------
    f : callable
        The drift coefficient, the deterministic part of the SDE.
    g : callable, float
        The diffusion coefficient, the stochastic part.
    dt : None, float
        Precision of numerical integration.

    Returns
    -------
    func : callable
        The one-step numerical integration function.
    """
    dt = profile.get_dt() if dt is None else dt
    dt_sqrt = np.sqrt(dt)
    f = autojit(f)

    if callable(g):
        g = autojit(g)

        def int_fg(y0, t, *args):
            dW = np.random.normal(0.0, 1.0, y0.shape)
            df = f(y0, t - dt, *args) * dt
            g_n = g(y0, t - dt, *args)
            dg = g_n * dW * dt_sqrt
            y_n_bar = y0 + df + g_n * dt_sqrt
            g_n_bar = g(y_n_bar, t, *args)
            extra_term = 0.5 * (g_n_bar - g_n) * (dW * dW * dt_sqrt)
            y1 = y0 + df + dg + extra_term
            return y1
    else:
        assert isinstance(g, (int, float, np.ndarray))

        def int_fg(y0, t, *args):
            dW = np.random.normal(0.0, 1.0, y0.shape)
            df = f(y0, t - dt, *args) * dt
            dg = g * dW * dt_sqrt
            y1 = y0 + df + dg
            return y1

    return autojit(int_fg)
Пример #9
0
def Euler_method(f, g, dt=None):
    """Itô stochastic integral. The simplest stochastic numerical approximation
        is the Euler-Maruyama method. Its is an order 0.5 strong Taylor schema.
        Also named as ``EM``, ``EM_method``, ``Euler``, ``Euler_Maruyama_method``.

        Parameters
        ----------
        f : callable
            The drift coefficient, the deterministic part of the SDE.
        g : callable, float
            The diffusion coefficient, the stochastic part.
        dt : None, float
            Precision of numerical integration.

        Returns
        -------
        func : callable
            The one-step numerical integration function.
        """
    dt = profile.get_dt() if dt is None else dt
    dt_sqrt = np.sqrt(dt)
    f = autojit(f)

    if callable(g):
        g = autojit(g)

        def int_fg(y0, t, *args):
            dW = np.random.normal(0.0, 1.0, y0.shape)
            df = f(y0, t, *args) * dt
            dg = dt_sqrt * g(y0, t, *args) * dW
            return y0 + df + dg
    else:
        assert isinstance(g, (int, float, np.ndarray))

        def int_fg(y0, t, *args):
            dW = np.random.normal(0.0, 1.0, y0.shape)
            df = f(y0, t, *args) * dt
            dg = dt_sqrt * g * dW
            return y0 + df + dg

    return autojit(int_fg)
Пример #10
0
    def __init__(self, **kwargs):
        if 'args' in kwargs:
            kwargs.pop('args')
        if 'kwargs' in kwargs:
            kwargs.pop('kwargs')
        for k, v in kwargs.items():
            setattr(self, k, v)

        # define external connections
        self.pre_synapses = []
        self.post_synapses = []

        # check functions
        assert 'update_state' in kwargs
        self.update_state = helper.autojit(self.update_state)

        # check `geometry`
        assert 'geometry' in kwargs, 'Must define "geometry".'
        assert 'num' in kwargs, 'Must define "num".'

        # check `name`
        if 'name' not in kwargs:
            global _neuron_no
            self.name = "Neurons-{}".format(_neuron_no)
            _neuron_no += 1

        # check `state`
        assert 'state' in kwargs, 'Must define "state".'

        # check `var2index`
        if 'var2index' not in kwargs:
            raise ValueError('Must define "var2index".')
        assert isinstance(self.var2index, dict), '"var2index" must be a dict.'
        for k, _ in self.default_variables:
            if k in self.var2index:
                if k == 'V':
                    if self.var2index['V'] != 0:
                        print('The position of "V" is not 0.')
                else:
                    raise ValueError('"{}" is a pre-defined variable, cannot '
                                     'be defined in "var2index".'.format(k))
        user_defined_variables = sorted(list(self.var2index.items()),
                                        key=lambda a: a[1])
        neu_variables = user_defined_variables + self.default_variables
        var2index_array = np.zeros((len(neu_variables), ), dtype=np.int32)
        vars = dict()
        for i, (var, index) in enumerate(neu_variables):
            var2index_array[i] = index
            vars[var] = i
        self.var2index = vars
        self.var2index_array = var2index_array
Пример #11
0
def exponential_euler(f, factor_zero_order, factor_one_order, dt=None):
    """Order 2 Exponential Euler method.

    For an equation of the form

    .. math:

        y^{\\prime}=f(y), \quad y(0)=y_{0}

    its schema is given by

    .. math:

        y_{n+1}=y_{n}+h \\varphi(hA) f (y_{n})

    where :math::`A=f^{\prime}(y_{n})` and
    :math::`\\varphi(z)=\\frac{e^{z}-1}{z}`.

    Parameters
    ----------
    f : callable
        The function at the right hand of the differential equation.
    dt : None, float
    factor_zero_order : int, float
        The factor of the zero order function in the equation.
    factor_one_order : int, float
        The factor of the one order function in the equation.

    Returns
    -------
    func : callable
        The one-step numerical integration function.
    """

    a = np.exp(-factor_one_order * dt)
    b = factor_zero_order / factor_one_order * (1 - a)

    def int_f(y0, t, *args):
        y0 = f(y0, t, *args)
        return y0 * a + b

    return autojit(int_f)
Пример #12
0
def syn_delay(func):

    func = helper.autojit(func)

    @helper.autojit
    def f(syn_state, t, var2index):
        # get `g`
        g = func(syn_state, t)
        # get `delay_len`
        delay_len = var2index[-1, 0]
        # update `output_idx`
        output_idx = (var2index[-2, 1] + 1) % delay_len
        var2index[-2, 1] = output_idx
        # update `delay_idx`
        delay_idx = (var2index[-3, 1] + 1) % delay_len
        var2index[-3, 1] = delay_idx
        # update `conductance`
        syn_state[1][delay_idx] = g

    return f
Пример #13
0
def generate_fake_neuron(num, V=0.):
    """Generate the fake neuron group for testing synapse function.

    Parameters
    ----------
    num : int
        Number of neurons in the group.
    V : int, float, numpy.ndarray
        Initial membrane potential.

    Returns
    -------
    neurons : dict
        An instance of ``Dict`` for simulating neurons.
    """

    var2index = dict(V=0)
    num, geometry = num, (num, )
    state = np.zeros((5, num))
    state[0] = V
    update_state = helper.autojit(lambda neu_state, t: 1)
    return Neurons(**locals())
Пример #14
0
    def __init__(self, **kwargs):
        if 'kwargs' in kwargs:
            kwargs.pop('kwargs')
        for k, v in kwargs.items():
            setattr(self, k, v)

        self.post.pre_synapses.append(self)
        self.pre.post_synapses.append(self)

        # check functions
        assert 'update_state' in kwargs, 'Must provide "update_state" function.'

        if 'output_synapse' not in kwargs:
            def f1(syn_state, var_index, neu_state):
                output_idx = var_index[-2]
                neu_state[-1] += syn_state[output_idx[0]][output_idx[1]]

            self.output_synapse = f1

        if 'collect_spike' not in kwargs:
            def f2(syn_state, pre_neu_state, post_neu_state):
                syn_state[0][-1] = pre_neu_state[-3]

            self.collect_spike = f2

        self.update_state = helper.autojit(self.update_state)
        self.output_synapse = helper.autojit(self.output_synapse)
        self.collect_spike = helper.autojit(self.collect_spike)

        # check `name`
        if 'name' not in kwargs:
            global synapse_no
            self.name = "Synapses-{}".format(synapse_no)
            synapse_no += 1

        # check `num`, `num_pre` and `num_post`
        assert 'num' in kwargs, 'Must provide "num" attribute.'
        if 'num_pre' not in kwargs:
            self.num_pre = self.pre.num
        if 'num_post' not in kwargs:
            self.num_post = self.post.num

        # check `delay_len`
        if 'delay_len' not in kwargs:
            if 'delay' not in kwargs:
                raise ValueError('Must define "delay".')
            else:
                dt = kwargs.get('dt', profile.get_dt())
                self.delay_len = format_delay(self.delay, dt)

        # check `var2index`
        if 'var2index' not in kwargs:
            raise ValueError('Must define "var2index".')
        assert isinstance(self.var2index, dict), '"var2index" must be a dict.'
        # "g" is the "delay_idx"
        # 'g_post' is the "output_idx"
        default_variables = [('pre_spike', (0, -1)),
                             ('g', (1, self.delay_len - 1)),
                             ('g_post', (1, 0)), ]
        self.default_variables = default_variables
        for k, _ in default_variables:
            if k in self.var2index:
                raise ValueError('"{}" is a pre-defined variable, '
                                 'cannot be defined in "var2index".'.format(k))
        user_defined_variables = sorted(list(self.var2index.items()), key=lambda a: a[1])
        syn_variables = user_defined_variables + default_variables
        var2index_array = np.zeros((len(syn_variables) + 1, 2), dtype=np.int32)
        var2index_array[-1, 0] = self.delay_len
        vars = dict(delay_len=-1)
        for i, (var, index) in enumerate(syn_variables):
            var2index_array[i] = list(index)
            vars[var] = i
        self.var2index = vars
        self.var2index_array = var2index_array
Пример #15
0
 def __init__(self, target):
     self.target = target
     self.update_state = helper.autojit(self.update_state)