Source code for axon_sdk.networks.functional.signed_multipler_norm

from axon_sdk.primitives import (
    SpikingNetworkModule,
    DataEncoder,
)
from axon_sdk.networks import MultiplierNetwork, ScalarMultiplierNetwork
from typing import Optional


[docs] class SignedMultiplierNormNetwork(SpikingNetworkModule): """ Module composed of a signed multiplier followed by a scalar multiplier. Given two input values x1 and x2 in the range [0,1] and a factor in the range [0,100], the output is: output = (x1 * x2) * factor > IMPORTANT: It's the user's responsability to guarantee that (x1 * x2) * factor < 1. Otherwise, the network will misbehave due to the overflow. This block is useful to perform multiplication over an extended range of inputs beyond [0,1]. For example, to multiply 13 and 7 the block can be used as follows: x1 = 13 / 100 x2 = 7 / 100 factor = 100 output = (13 * 7) / 100 Denormalizing the output by multiplying by 100 will yield a result in the original range """ def __init__(self, encoder: DataEncoder, factor: float, module_name: Optional[str] = None) -> None: super().__init__(module_name) self.encoder = encoder # Parameters Vt = 10.0 tm = 100.0 tf = 20.0 Tsyn = 1.0 Tmin = encoder.Tmin we = Vt wi = -Vt # Create multiplier network self.mn = MultiplierNetwork(encoder, module_name='mul_net') self.add_subnetwork(self.mn) self.scmn = ScalarMultiplierNetwork(factor=factor, encoder=encoder, module_name='scalar_mul') self.add_subnetwork(self.scmn) self.input1_plus = self.add_neuron( Vt, tm, tf, neuron_name="input1_plus" ) self.input1_minus = self.add_neuron( Vt, tm, tf, neuron_name="input1_minus" ) self.input2_plus = self.add_neuron( Vt, tm, tf, neuron_name="input2_plus" ) self.input2_minus = self.add_neuron( Vt, tm, tf, neuron_name="input2_minus" ) self.output_plus = self.add_neuron( Vt, tm, tf, neuron_name="output_plus" ) self.output_minus = self.add_neuron( Vt, tm, tf, neuron_name="output_minus" ) self.sign1 = self.add_neuron(Vt, tm, tf, neuron_name="sign1") self.sign2 = self.add_neuron(Vt, tm, tf, neuron_name="sign2") self.sign3 = self.add_neuron(Vt, tm, tf, neuron_name="sign3") self.sign4 = self.add_neuron(Vt, tm, tf, neuron_name="sign4") self.connect_neurons(self.input1_plus, self.mn.input1, "V", we, Tsyn) self.connect_neurons(self.input1_minus, self.mn.input1, "V", we, Tsyn) self.connect_neurons(self.input2_plus, self.mn.input2, "V", we, Tsyn) self.connect_neurons(self.input2_minus, self.mn.input2, "V", we, Tsyn) self.connect_neurons(self.input1_plus, self.sign1, "V", 0.25 * we, Tsyn) self.connect_neurons(self.input1_plus, self.sign3, "V", 0.25 * we, Tsyn) self.connect_neurons(self.input1_minus, self.sign2, "V", 0.25 * we, Tsyn) self.connect_neurons(self.input1_minus, self.sign4, "V", 0.25 * we, Tsyn) self.connect_neurons(self.input2_plus, self.sign1, "V", 0.25 * we, Tsyn) self.connect_neurons(self.input2_plus, self.sign2, "V", 0.25 * we, Tsyn) self.connect_neurons(self.input2_minus, self.sign3, "V", 0.25 * we, Tsyn) self.connect_neurons(self.input2_minus, self.sign4, "V", 0.25 * we, Tsyn) self.connect_neurons(self.sign1, self.sign2, "V", 0.5 * wi, Tsyn) self.connect_neurons(self.sign1, self.sign3, "V", 0.5 * wi, Tsyn) self.connect_neurons(self.sign2, self.sign1, "V", 0.5 * wi, Tsyn) self.connect_neurons(self.sign2, self.sign4, "V", 0.5 * wi, Tsyn) self.connect_neurons(self.sign3, self.sign1, "V", 0.5 * wi, Tsyn) self.connect_neurons(self.sign3, self.sign4, "V", 0.5 * wi, Tsyn) self.connect_neurons(self.sign4, self.sign2, "V", 0.5 * wi, Tsyn) self.connect_neurons(self.sign4, self.sign3, "V", 0.5 * wi, Tsyn) self.connect_neurons(self.mn.output, self.scmn.input, "V", we, Tsyn) self.connect_neurons(self.scmn.output, self.output_plus, "V", we, Tsyn) self.connect_neurons(self.scmn.output, self.output_minus, "V", we, Tsyn) self.connect_neurons(self.sign1, self.output_minus, "V", 2 * wi, Tsyn) self.connect_neurons(self.sign2, self.output_plus, "V", 2 * wi, Tsyn) self.connect_neurons(self.sign3, self.output_plus, "V", 2 * wi, Tsyn) self.connect_neurons(self.sign4, self.output_minus, "V", 2 * wi, Tsyn)
if __name__ == "__main__": from axon_sdk.simulator import Simulator norm = 100 encoder = DataEncoder(Tmin=10.0, Tcod=150.0) net = SignedMultiplierNormNetwork(encoder, factor=norm, module_name='signmul_net') sim = Simulator(net, encoder, dt=0.0005) x1 = 42.32 x2 = 2.15 true_product = x1 * x2 val1 = x1 / norm val2 = x2 / norm # Apply both input values if val1 > 0: sim.apply_input_value(abs(val1), neuron=net.input1_plus, t0=0) else: sim.apply_input_value(abs(val1), neuron=net.input1_minus, t0=0) if val2 > 0: sim.apply_input_value(abs(val2), neuron=net.input2_plus, t0=0) else: sim.apply_input_value(abs(val2), neuron=net.input2_minus, t0=0) # Simulate long enough to see output sim.simulate(simulation_time=500) spikes_plus = sim.spike_log.get(net.output_plus.uid, []) spikes_minus = sim.spike_log.get(net.output_minus.uid, []) if len(spikes_plus) == 2: print("Output + has 2 spikes") interval = spikes_plus[1] - spikes_plus[0] decoded_val = encoder.decode_interval(interval) if len(spikes_minus) == 2: print("Output - has 2 spikes") interval = spikes_minus[1] - spikes_minus[0] decoded_val = -1 * encoder.decode_interval(interval) if len(spikes_plus) != 2 and len(spikes_minus) != 2: print(f"❌ Output spike missing or incomplete") raise ValueError print(f"✅ Input: {x1} × {x2}") print(f"✅ Expected: {true_product:.4f}") print(f"✅ Output spike interval: {interval:.3f} ms") print(f"✅ Decoded value: {decoded_val:.4f}") print(f"✅ Decoded and Denormalized value : {norm * decoded_val:.4f}") print("multiplier decoded val") spikes = sim.spike_log.get(net.mn.output.uid, []) print(encoder.decode_interval(spikes[1] - spikes[0]))