Tutorial 4: Adding Subnetworks

Here we will add various subnetworks, derived from the following paper:

NS Szczecinski, AJ Hunt, RD Quinn. A functional subnetwork approach to designing synthetic nervous systems that control legged robot locomotion. Frontiers in neurorobotics, 2017

[1]:
# Add the library to the path
# If jupyter cannot find SNS-Toolbox
import os
import sys
module_path = os.path.abspath(os.path.join('..'))
if module_path not in sys.path:
    sys.path.append(module_path)

from sns_toolbox.networks import Network #, AdditionNetwork (This would import the code that we remake here
from sns_toolbox.neurons import NonSpikingNeuron
from sns_toolbox.connections import NonSpikingTransmissionSynapse
from sns_toolbox.networks import DivisionNetwork, MultiplicationNetwork, DifferentiatorNetwork
from sns_toolbox.networks import IntegratorNetwork
from sns_toolbox.renderer import render

# Let's define a custom functional subnetwork 'preset', in this case a network which takes a weighted sum of inputs

class AdditionNetwork(Network): # Note that this network is also a preset available from sns_toolbox.networks
    """
    Network which performs addition or subtraction of multiple inputs. Currently only supports non-spiking neurons.

    :param gains:       List of addition or subtraction weights.
    :type gains:        list, np.ndarray, or torch.tensor
    :param add_del_e:   Reversal potential of addition synapses, default is 100. Unit is millivolts (mV).
    :type add_del_e:    Number, optional
    :param sub_del_e:   Reversal potential of subtraction synapses, default is -40. Unit is millivolts (mV).
    :type sub_del_e:    Number, optional
    :param neuron_type: Neuron preset to use, default is sns_toolbox.design.neurons.NonSpikingNeuron.
    :type neuron_type:  sns_toolbox.design.neurons.NonSpikingNeuron, optional
    :param name:        Name of this network, default is 'Add'.
    :type name:         str, optional
    """
    def __init__(self,gains,add_del_e=100,sub_del_e=-40,neuron_type=NonSpikingNeuron(),name='Add', R=20.0, **kwargs):
        super().__init__(name=name,**kwargs)
        num_inputs = len(gains)
        self.add_neuron(neuron_type=neuron_type, name=name + 'Sum')
        for i in range(num_inputs):
            self.add_neuron(neuron_type, name=name + 'Src' + str(i))
            gain = gains[i]
            if gain > 0:
                conn = NonSpikingTransmissionSynapse(gain=gain, reversal_potential=add_del_e, e_lo=neuron_type.params['resting_potential'], e_hi=neuron_type.params['resting_potential']+R)
            else:
                conn = NonSpikingTransmissionSynapse(gain=gain, reversal_potential=sub_del_e, e_lo=neuron_type.params['resting_potential'], e_hi=neuron_type.params['resting_potential']+R)
            self.add_connection(conn, i + 1, name + 'Sum')

# Now let's import our network into another one, as we would normally use this functionality
net = Network(name='Tutorial 4 Network')

sum_net = AdditionNetwork([1,-1,-0.5,2])
net.add_network(sum_net, color='blue')
render(net)
[1]:
../_images/tutorials_tutorial_4_1_0.svg
[2]:
# We can add more subnetworks
div_net = DivisionNetwork(1,0.5)
net.add_network(div_net, color='orange')
render(net)
[2]:
../_images/tutorials_tutorial_4_2_0.svg
[3]:
mult_net = MultiplicationNetwork()
net.add_network(mult_net, color='green')
render(net)
[3]:
../_images/tutorials_tutorial_4_3_0.svg
[4]:
diff_net = DifferentiatorNetwork()
net.add_network(diff_net,color='red')
render(net)
[4]:
../_images/tutorials_tutorial_4_4_0.svg
[5]:
int_net = IntegratorNetwork()
net.add_network(int_net,color='purple')
render(net)
[5]:
../_images/tutorials_tutorial_4_5_0.svg
[ ]: