diff options
| author | Tanner Robison <[email protected]> | 2026-06-26 19:13:44 -0700 |
|---|---|---|
| committer | Tanner Robison <[email protected]> | 2026-06-29 19:44:13 -0700 |
| commit | 3a17db637fd41015df26f1cceb0d1c098e85d436 (patch) | |
| tree | 34b6913348444b6ff2b47218eafa7ad9748e574f /spires_memristor_sim/spires_interface.py | |
| parent | 3c9a3d7d92d155545ce4892524f00dcd092b52d3 (diff) | |
spires python memTorch interface
Implemented an interface for memTorch to talk to spires. memTorch is
used for calculating the weights and are passed to spires for
determining the spikes
readout layer has still not been implemented, no way of actually reading
the output
Diffstat (limited to 'spires_memristor_sim/spires_interface.py')
| -rw-r--r-- | spires_memristor_sim/spires_interface.py | 119 |
1 files changed, 100 insertions, 19 deletions
diff --git a/spires_memristor_sim/spires_interface.py b/spires_memristor_sim/spires_interface.py index 3f1e302..b7e5fff 100644 --- a/spires_memristor_sim/spires_interface.py +++ b/spires_memristor_sim/spires_interface.py @@ -1,35 +1,116 @@ import ctypes import numpy import torch +import random -spires_lib = ctypes.CDLL("../spires/build/.libspires.so") +LIF_DISCRETE = 0 -spires_lib.spires_reservoir_step.argtypes = [ctypes.POINTER(ctypes.c_float)] -spires_lib.spires_reservoir_step.restype = None +#load the spires library +spires_lib = ctypes.CDLL("../spires/lib/libspires.so") + +# C signautes for creating reservoir +spires_lib.create_reservoir.argtypes = [ + ctypes.c_size_t, + ctypes.c_size_t, + ctypes.c_size_t, + ctypes.c_double, + ctypes.c_double, + ctypes.c_double, + ctypes.c_double, + ctypes.c_double, + ctypes.c_int, + ctypes.c_int, + ctypes.POINTER(ctypes.c_double) +] +spires_lib.create_reservoir.restype = ctypes.c_void_p + +# C signatures for reservoir destruction +spires_lib.free_reservoir.argtypes = [ctypes.c_void_p] +spires_lib.free_reservoir.restype = None + +# C signatures for step reservoir function +spires_lib.update_neuron.argtypes = [ + ctypes.c_void_p, #Pointer to spires reservoir struct + ctypes.c_int, + ctypes.c_double, + ctypes.c_double +] +spires_lib.update_neuron.restype = None + +# C signatures for get neuron spike function +spires_lib.read_reservoir_spikes.argtypes = [ + ctypes.c_void_p, + ctypes.POINTER(ctypes.c_float) +] +spires_lib.read_reservoir_spikes.restype = None + +def init_spires_reservoir(reservoir_size): + print("Creating spires reservoir") + + neuron_parameters = (ctypes.c_double * 4)(0.0, 1.0, 0.2, 0.5) + c_neuron_parameters = ctypes.cast(neuron_parameters, ctypes.POINTER(ctypes.c_double)) + + reservoir_ptr = spires_lib.create_reservoir( + ctypes.c_size_t(int(reservoir_size)), # num neurons + ctypes.c_size_t(int(reservoir_size)), # num neurons + ctypes.c_size_t(2), # num_outputs + ctypes.c_double(0.9), # spectral radius + ctypes.c_double(0.8), # ei_ratio + ctypes.c_double(1.0), # input_strength + ctypes.c_double(0.1), # connectivity + ctypes.c_double(1.0), # dt + ctypes.c_int(1), # connectivity type ( 1 = sparse) + ctypes.c_int(LIF_DISCRETE), # neuron type + c_neuron_parameters # neuron params + ) + + #allocate empty void pointer, (reservoir will go here) + if not reservoir_ptr: + raise RuntimeError(f"Spires faile to initialize the reservoir: {status_code}") + else: + print("Spires reservoir initialized") + + # reservoir_ptr._keep_alive = neuron_parameters + + return reservoir_ptr + +def free_spires_reservoir(reservoir_ptr): + print("Freeing the spires reservoir") + spires_lib.free_reservoir(reservoir_ptr) + return 0 + #change currents from tensor to a flat C pointer array for spires to read -def send_currents_to_spires(currents): +def send_currents_to_spires(reservoir_ptr, currents_tensor): + print("Sending currents to spires") # ----- extract from pytorhc graph ----- # .detach() removes it from auto gradient tracking # .cpu() make sure data is in RAM, not VRAM # .numpy() maps it to numpy array - numpy_array = torch_tensor.detach().cpu().numpy() - - # ----- makes suren layout matches 32 bit float C-array ----- - # .astype(npfloat32) forces standard CC float precistion + # ----- makes suren layout matches 64 bit double C-array ----- + # .astype(npfloat64) forces standard CC float precistion # .flatten() makes sure the memory is a 1D block - contiguous_array = numpy_array.astype(np.float32).flatten() + numpy_array = currents_tensor.detach().cpu().numpy().astype(numpy.float64).flatten() - # ----- Ensure raw memory pointer ----- - c_float_ptr = contiguous_array.ctypes.data_as(ctypes.POINTER(ctypes.c_float)) - array_size = contiguous_array.size + some_ptr = ctypes.cast(reservoir_ptr, ctypes.POINTER(ctypes.POINTER(ctypes.c_void_p))) - # ----- Call the C library ----- - spires_lib.spires_reservoir_step(c_float_ptr, array_size) - return contiguous_array + neurons_array = some_ptr[0] - # NEED TO MODIFY SPIRES FOR THIS?? :(( + print("updating the neurons") + for i in range(len(numpy_array)): + neuron_ptr = neurons_array[i] + input_current = numpy_array[i] -def read_spikes_from_spires(): - placeholder = 0 - return 0 + spires_lib.update_neuron(neuron_ptr, LIF_DISCRETE, input_current, 1.0) + + return numpy_array + +def read_spikes_from_spires(reservoir_ptr, size=0): + print("Recieved spikes from spires") + #didnt do any safety checking womp womp + returned_spikes = numpy.zeros(size, dtype=numpy.float64) + c_spike_ptr = returned_spikes.ctypes.data_as(ctypes.POINTER(ctypes.c_float)) + + spires_lib.read_reservoir_spikes(reservoir_ptr, c_spike_ptr) + + return returned_spikes |
