# Path: snntoolbox/parsing/utils.py
# @abstractmethod
# def get_inbound_layers(self, layer):
#     """Get inbound layers of ``layer``.
# 
#     Returns
#     -------
# 
#     inbound: Sequence
#     """
# 
#     pass


import os
import json
import warnings
import numpy as np
import theano
from keras import backend as k
from keras.layers import Dense, Flatten, AveragePooling2D, MaxPooling2D, Conv2D
from keras.layers import Layer, Concatenate
from snntoolbox.parsing.utils import get_inbound_layers
        from snntoolbox.utils.utils import get_abs_path
        from snntoolbox.bin.utils import get_log_keys, get_plot_keys
        """
        Get a new value for the bias, relaxing it over time to the true value.
        """

        i = self.get_layer_idx()
        return self.b0 * k.minimum(k.maximum(
            0, 1 - (1 - 2 * self.time / self.duration) * i / 50), 1)


def add_payloads(prev_layer, input_spikes):
    """Get payloads from previous layer."""

    # Get only payloads of those pre-synaptic neurons that spiked
    payloads = k.T.set_subtensor(
        prev_layer.payloads[k.T.nonzero(k.equal(input_spikes, 0.))], 0.)
    print("Using spikes with payloads from layer {}".format(prev_layer.name))
    return k.T.add(input_spikes, payloads)


def spike_call(call):
    def decorator(self, x):

        if clamp_var:
            # Clamp membrane potential if spike rate variance too high
            self.update_avg_variance(x)
        if self.online_normalization:
            # Modify threshold if firing rate of layer too low
            self.add_update([(self.v_thresh, self.get_new_thresh())])
        if self.payloads:
            # Add payload from previous layer

# Path: snntoolbox/parsing/utils.py
# @abstractmethod
# def get_inbound_layers(self, layer):
#     """Get inbound layers of ``layer``.
# 
#     Returns
#     -------
# 
#     inbound: Sequence
#     """
# 
#     pass


# Path: snntoolbox/simulation/backends/inisim/temporal_mean_rate_theano.py
import os
import json
import warnings
import numpy as np
import theano
from keras import backend as k
from keras.layers import Dense, Flatten, AveragePooling2D, MaxPooling2D, Conv2D
from keras.layers import Layer, Concatenate
from snntoolbox.parsing.utils import get_inbound_layers
        from snntoolbox.utils.utils import get_abs_path
        from snntoolbox.bin.utils import get_log_keys, get_plot_keys

        """
        Get a new value for the bias, relaxing it over time to the true value.
        """

        i = self.get_layer_idx()
        return self.b0 * k.minimum(k.maximum(
            0, 1 - (1 - 2 * self.time / self.duration) * i / 50), 1)


def add_payloads(prev_layer, input_spikes):
    """Get payloads from previous layer."""

    # Get only payloads of those pre-synaptic neurons that spiked
    payloads = k.T.set_subtensor(
        prev_layer.payloads[k.T.nonzero(k.equal(input_spikes, 0.))], 0.)
    print("Using spikes with payloads from layer {}".format(prev_layer.name))
    return k.T.add(input_spikes, payloads)


def spike_call(call):
    def decorator(self, x):

        if clamp_var:
            # Clamp membrane potential if spike rate variance too high
            self.update_avg_variance(x)
        if self.online_normalization:
            # Modify threshold if firing rate of layer too low
            self.add_update([(self.v_thresh, self.get_new_thresh())])
        if self.payloads:
            # Add payload from previous layer

            x = add_payloads(get_inbound_layers(self)[0], x)