summaryrefslogtreecommitdiff
path: root/old_python/spires_interface.py
blob: 3d307ad95bb9535d451620792d27fd38f2cfc9b8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
import ctypes
import numpy
import torch
import random

LIF_DISCRETE = 0

#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),                # spectral radius
            ctypes.c_double(0.8),                # ei_ratio
            ctypes.c_double(1.0),                # input_strength
            ctypes.c_double(0.0),                # 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(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
    # ----- 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
    numpy_array = currents_tensor.detach().cpu().numpy().astype(numpy.float64).flatten()

    some_ptr = ctypes.cast(reservoir_ptr, ctypes.POINTER(ctypes.POINTER(ctypes.c_void_p)))

    neurons_array = some_ptr[0]

    # print("updating the neurons")
    for i in range(len(numpy_array)):
        neuron_ptr = neurons_array[i]
        input_current = numpy_array[i]

        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