From f4854ae4c816a7718c88b3b0d230c24786553f26 Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 30 Jul 2026 12:36:31 -0700 Subject: SPICE crossbar readout layer --- src/crossbar_generator.a | Bin 0 -> 17776 bytes src/crossbar_generator.c | 347 +- src/crossbar_generator.h | 46 +- src/crossbar_generator.o | Bin 18040 -> 0 bytes src/main | Bin 47368 -> 258376 bytes src/main.a | Bin 0 -> 24280 bytes src/main.c | 669 ++-- src/main.o | Bin 25704 -> 0 bytes src/makefile | 4 +- src/read_crossbar.a | Bin 0 -> 15584 bytes src/read_crossbar.c | 331 +- src/read_crossbar.h | 25 +- src/read_crossbar.o | Bin 11984 -> 0 bytes src/reservoir_raster.svg | 8118 ---------------------------------------------- src/spires_interface.a | Bin 0 -> 13208 bytes src/spires_interface.c | 358 +- src/spires_interface.h | 62 +- src/spires_interface.o | Bin 10800 -> 0 bytes 18 files changed, 937 insertions(+), 9023 deletions(-) create mode 100644 src/crossbar_generator.a delete mode 100644 src/crossbar_generator.o create mode 100644 src/main.a delete mode 100644 src/main.o create mode 100644 src/read_crossbar.a delete mode 100644 src/read_crossbar.o create mode 100644 src/spires_interface.a delete mode 100644 src/spires_interface.o diff --git a/src/crossbar_generator.a b/src/crossbar_generator.a new file mode 100644 index 0000000..f7a9677 Binary files /dev/null and b/src/crossbar_generator.a differ diff --git a/src/crossbar_generator.c b/src/crossbar_generator.c index cae05bc..3db1adc 100644 --- a/src/crossbar_generator.c +++ b/src/crossbar_generator.c @@ -1,188 +1,203 @@ -#include #include "crossbar_generator.h" +#include -static int validate_config(const Crossbar_Config *config) { - printf("validating configs...\n"); - if (config == NULL) { - return -1; - } - if (config->rows == 0) { - return -1; - } - if (config->columns == 0) { - return -1; - } - if (config->input_series == NULL) { - return -1; - } - if (config->num_samples == 0) { - return -1; - } - if (config->initial_resistance == NULL) { - return -1; - } - if (config->model_path == NULL) { - return -1; - } - if (config->subcircuit_name == NULL) { - return -1; - } - if (config->load_resistance <= 0.0) { - return -1; - } - if (config->time_step <= 0.0) { - return -1; - } - if (config->stop_time <= 0.0) { - return -1; - } - if (config->print_state_nodes != 0 && config->print_state_nodes != 1) { - return -1; - } - return 0; +static int validate_config(const Crossbar_Config *config) +{ + printf("validating configs...\n"); + if (config == NULL) { + return -1; + } + if (config->rows == 0) { + return -1; + } + if (config->columns == 0) { + return -1; + } + if (config->input_series == NULL) { + return -1; + } + if (config->num_samples == 0) { + return -1; + } + if (config->initial_resistance == NULL) { + return -1; + } + if (config->model_path == NULL) { + return -1; + } + if (config->subcircuit_name == NULL) { + return -1; + } + if (config->load_resistance <= 0.0) { + return -1; + } + if (config->time_step <= 0.0) { + return -1; + } + if (config->stop_time <= 0.0) { + return -1; + } + if (config->print_state_nodes != 0 && config->print_state_nodes != 1) { + return -1; + } + return 0; } -//thus starts fprintf hell... -static int write_header(FILE *file, const Crossbar_Config *config) { - if (fprintf(file, "* Generating a crossbar with:\n" - "*Rows: %zu\n" - "*Columns: %zu\n", - config->rows, config->columns ) < 0) { - fprintf(stderr, "Failed to write header at crossbar size"); - return -1; - } - - //include the memristor model - if (fprintf(file, "\n.include \"%s\"\n", config->model_path) < 0) { - fprintf(stderr, "Faile to write header at .include memristor"); - return -1; - } - - return 0; +// thus starts fprintf hell... +static int write_header(FILE *file, const Crossbar_Config *config) +{ + if (fprintf(file, + "* Generating a crossbar with:\n" + "*Rows: %zu\n" + "*Columns: %zu\n", + config->rows, config->columns) < 0) { + fprintf(stderr, "Failed to write header at crossbar size"); + return -1; + } + + // include the memristor model + if (fprintf(file, "\n.include \"%s\"\n", config->model_path) < 0) { + fprintf(stderr, "Faile to write header at .include memristor"); + return -1; + } + + return 0; } -static int write_input_series(FILE *file, const Crossbar_Config *config) { - fprintf(file, "\n* SPIRES reservoir states\n"); +static int write_input_series(FILE *file, const Crossbar_Config *config) +{ + fprintf(file, "\n* SPIRES reservoir states\n"); - for (size_t row = 0; row < config->rows; row++) { - fprintf(file, "VROW%zu row%zu 0 PWL(", row, row); + for (size_t row = 0; row < config->rows; row++) { + fprintf(file, "VROW%zu row%zu 0 PWL(", row, row); - for (size_t sample = 0; sample < config->num_samples; sample++) { - double time = sample * config->time_step; - double state = config->input_series[sample * config->rows + row]; + for (size_t sample = 0; sample < config->num_samples; + sample++) { + double time = sample * config->time_step; + double state = + config->input_series[sample * config->rows + row]; - //scale neuron states to safe read voltages - double voltage = state * 0.1; + double voltage = state; - fprintf(file, "%.17g %.17g ", time, voltage); - } - fprintf(file, ")\n"); - } - return ferror(file) ? -1 : 0; + fprintf(file, "%.17g %.17g ", time, voltage); + } + fprintf(file, ")\n"); + } + return ferror(file) ? -1 : 0; } -static int write_memristor_array(FILE *file, const Crossbar_Config *config) { - if (fprintf(file, "\n* Memristor Array\n") < 0) { - fprintf(stderr, "Failed to write memristor array comment label thing"); - return -1; - } - - for (size_t row = 0; row < config->rows; row++) { - for (size_t column = 0; column < config->columns; column++) { - //initial_resistance here is done wrong, need to fix - if (fprintf(file, - "X%zu%zu row%zu col%zu %s" - " PARAMS: Rinit=%.0f\n", row, column, row, column, - config->subcircuit_name, - config->initial_resistance[row * config->columns + column]) < 0) { - fprintf(stderr, "Failed to write memristor array"); - return -1; - } - } - printf("\n"); - } - return 0; +static int write_memristor_array(FILE *file, const Crossbar_Config *config) +{ + if (fprintf(file, "\n* Memristor Array\n") < 0) { + fprintf(stderr, + "Failed to write memristor array comment label thing"); + return -1; + } + + for (size_t row = 0; row < config->rows; row++) { + for (size_t column = 0; column < config->columns; column++) { + // initial_resistance here is done wrong, need to fix + if (fprintf(file, + "X%zu%zu row%zu col%zu %s" + " PARAMS: Rinit=%.12g\n", + row, column, row, column, + config->subcircuit_name, + config->initial_resistance + [row * config->columns + column]) < 0) { + fprintf(stderr, + "Failed to write memristor array"); + return -1; + } + } + } + return 0; } -static int write_column_loads(FILE *file, const Crossbar_Config *config) { - if (fprintf(file, "\n* Column Loads\n") < 0) { - fprintf(stderr, "Failed to write column loads comment label thing"); - } - - for (size_t column = 0; column < config->columns; column++) { - if (fprintf(file, "RLOAD%zu col%zu 0 %.0f\n", column, column, - config->load_resistance) < 0) { - fprintf(stderr, "Failed to write column loads"); - return -1; - } - } - return 0; +static int write_column_loads(FILE *file, const Crossbar_Config *config) +{ + if (fprintf(file, "\n* Column Loads\n") < 0) { + fprintf(stderr, + "Failed to write column loads comment label thing"); + } + + for (size_t column = 0; column < config->columns; column++) { + if (fprintf(file, "RLOAD%zu col%zu 0 %.0f\n", column, column, + config->load_resistance) < 0) { + fprintf(stderr, "Failed to write column loads"); + return -1; + } + } + return 0; } -static int write_simulation(FILE *file, const Crossbar_Config *config) { - if (fprintf(file, "\n* Simulation\n") < 0) { - fprintf(stderr, "Failed to write simulation header"); - return -1; - } - - if (fprintf(file, ".tran %.17g %.17g uic\n.control\nrun\n", - config->time_step, config->stop_time) < 0) { - fprintf(stderr, "Failed to write simulation command"); - return -1; - } - return 0; +static int write_simulation(FILE *file, const Crossbar_Config *config) +{ + if (fprintf(file, "\n* Simulation\n") < 0) { + fprintf(stderr, "Failed to write simulation header"); + return -1; + } + + if (fprintf(file, ".tran %.17g %.17g uic\n.control\nrun\n", + config->time_step, config->stop_time) < 0) { + fprintf(stderr, "Failed to write simulation command"); + return -1; + } + return 0; } -static int write_save_date(FILE *file, const Crossbar_Config *config) { - fprintf(file, "linearize"); - for (int column = 0; column < config->columns; column++) { - if (fprintf(file, " v(col%zu)", column) < 0) { - fprintf(stderr, "Failed to write linearize statements"); - return -1; - } - } - - fprintf(file, "\nwrdata crossbar_output.dat"); - for (int column = 0; column < config->columns; column++) { - fprintf(file, " v(col%zu)", column); //ive given up on error checking - //Im doing too much of it - } - - if (fprintf(file, "\n.endc\n.end") < 0) { - fprintf(stderr, "Failed to write end statements"); - return -1; - } - return 0; +static int write_save_date(FILE *file, const Crossbar_Config *config) +{ + fprintf(file, "linearize"); + for (int column = 0; column < config->columns; column++) { + if (fprintf(file, " v(col%zu)", column) < 0) { + fprintf(stderr, "Failed to write linearize statements"); + return -1; + } + } + + fprintf(file, "\nwrdata crossbar_output.dat"); + for (int column = 0; column < config->columns; column++) { + fprintf(file, " v(col%zu)", + column); // ive given up on error checking + // Im doing too much of it + } + + if (fprintf(file, "\n.endc\n.end") < 0) { + fprintf(stderr, "Failed to write end statements"); + return -1; + } + return 0; } int generate_crossbar(const char *output_filename, - const Crossbar_Config *config) { - if (validate_config(config) < 0) { - fprintf(stderr, "invalid config"); - return -1; - } - - FILE *file = fopen(output_filename, "w"); - - if (file == NULL) { - fprintf(stderr, "could not create file"); - return -1; - } - - if (write_header(file, config) != 0 || - write_input_series(file, config) != 0 || - write_memristor_array(file, config) != 0 || - write_column_loads(file, config) != 0 || - write_simulation(file, config) != 0 || - write_save_date(file, config) != 0) { - - fclose(file); - return -1; - } - - if (fclose(file) != 0) { - fprintf(stderr, "failed to close output file"); - return -1; - } - return 0; + const Crossbar_Config *config) +{ + if (validate_config(config) < 0) { + fprintf(stderr, "invalid config"); + return -1; + } + + FILE *file = fopen(output_filename, "w"); + + if (file == NULL) { + fprintf(stderr, "could not create file"); + return -1; + } + + if (write_header(file, config) != 0 || + write_input_series(file, config) != 0 || + write_memristor_array(file, config) != 0 || + write_column_loads(file, config) != 0 || + write_simulation(file, config) != 0 || + write_save_date(file, config) != 0) { + + fclose(file); + return -1; + } + + if (fclose(file) != 0) { + fprintf(stderr, "failed to close output file"); + return -1; + } + return 0; } diff --git a/src/crossbar_generator.h b/src/crossbar_generator.h index e6ff4ae..d773fad 100644 --- a/src/crossbar_generator.h +++ b/src/crossbar_generator.h @@ -4,37 +4,37 @@ #include typedef struct { - size_t rows; //number of neurons - size_t columns; //number of outputs + size_t rows; // number of neurons + size_t columns; // number of outputs - //array of row input voltages. - //length must equal rows (# of rows) - const double *input_series; - size_t num_samples; + // array of row input voltages. + // length must equal rows (# of rows) + const double *input_series; + size_t num_samples; - //array of initial resistances - //stored in row-major order - //size must be rows * colums - const double *initial_resistance; + // array of initial resistances + // stored in row-major order + // size must be rows * colums + const double *initial_resistance; - //path to the memory component path - const char *model_path; + // path to the memory component path + const char *model_path; - //name of subcircuit(specific model) - const char *subcircuit_name; + // name of subcircuit(specific model) + const char *subcircuit_name; - //resistance from each column to ground - double load_resistance; + // resistance from each column to ground + double load_resistance; - //transient sim settings - double time_step; - double stop_time; + // transient sim settings + double time_step; + double stop_time; - //1 = true | 0 = false - int print_state_nodes; + // 1 = true | 0 = false + int print_state_nodes; } Crossbar_Config; -int generate_crossbar(const char *output_filename, - const Crossbar_Config *config); +int generate_crossbar(const char *output_filename, + const Crossbar_Config *config); #endif diff --git a/src/crossbar_generator.o b/src/crossbar_generator.o deleted file mode 100644 index f13a01f..0000000 Binary files a/src/crossbar_generator.o and /dev/null differ diff --git a/src/main b/src/main index 02aecf3..cf80398 100755 Binary files a/src/main and b/src/main differ diff --git a/src/main.a b/src/main.a new file mode 100644 index 0000000..2e8c08d Binary files /dev/null and b/src/main.a differ diff --git a/src/main.c b/src/main.c index e8a6d92..e238d96 100644 --- a/src/main.c +++ b/src/main.c @@ -1,407 +1,308 @@ -#include "spires_interface.h" #include "crossbar_generator.h" #include "read_crossbar.h" +#include "spires_interface.h" #include +#include #include #include #include -#include #define NUM_NEURONS 400 #define NUM_INPUTS 4 #define NUM_OUTPUTS 2 +#define NUM_CROSSBAR_COLUMNS (NUM_OUTPUTS * 2) #define NUM_TRAINING_STEPS 500 #define NUM_STEPS 2000 -#define SPIKE_THRESHOLD 0.5 +#define SPIKE_THRESHOLD 0.9 #define SPIKE_AMPLITUDE 0.1 #define PI 3.14159265358979323846 -static int plot_raster( - const Reservoir_State_Matrix *matrix, - size_t neurons_to_plot, - double spike_threshold -); - - -static int print_software_outputs( - spires_reservoir *reservoir, - const double *input_series, - size_t series_length, - size_t num_inputs, - size_t num_outputs, - size_t samples_to_print, - const char *label -); - -int main(void) { - //discrete LIF parameters for spires - double lif_config[] = { - 0.0, //V_off - 1.0, //V_th - 0.2, //leak rate - 0.5, //bias - }; - - const spires_reservoir_config config = { - .num_neurons = NUM_NEURONS, - .num_inputs = NUM_INPUTS, - .num_outputs = NUM_OUTPUTS, - .spectral_radius = 0.95, - .ei_ratio = 0.8, - .input_strength = 0.1, - .connectivity = 0.1, - .dt = 1.0, - .connectivity_type = SPIRES_CONN_RANDOM, - .neuron_type = SPIRES_NEURON_LIF_DISCRETE, - .neuron_params = lif_config - }; - - spires_reservoir *reservoir = NULL; - - spires_status status = spires_reservoir_create( - &config, - &reservoir - ); - - if (status != SPIRES_OK) { - fprintf(stderr, "Failed to create reservoir"); - return -1; - } - - //create training inputs - double training_inputs[NUM_TRAINING_STEPS * NUM_INPUTS]; - for (size_t timestep = 0; timestep < NUM_TRAINING_STEPS; timestep++) { - for (size_t input = 0; input < NUM_INPUTS; input++) { - training_inputs[timestep * NUM_INPUTS + input] = sin(2.0 * PI * (double)timestep / 50.0); - } - } - - //create target outputs - double target_outputs[NUM_TRAINING_STEPS * NUM_OUTPUTS]; - for (size_t timestep = 0; timestep < NUM_TRAINING_STEPS; timestep++) { - size_t next_timestep = (timestep + 1) % NUM_TRAINING_STEPS; - double target = sin(2.0 * PI * (double)next_timestep / 50.0); - for (size_t output = 0; output < NUM_OUTPUTS; output++) { - target_outputs[timestep * NUM_OUTPUTS + output] = target; - } - } - - Reservoir_State_Matrix state_matrix = {0}; - if (collect_reservoir_states(reservoir, training_inputs, NUM_TRAINING_STEPS, - &state_matrix) != 0) { - fprintf(stderr, "Failed to collect reservoir states"); - spires_reservoir_destroy(reservoir); - return -1; - } - printf("collected state matrix: %zu x %zu\n", state_matrix.num_samples, - state_matrix.num_features); - - print_software_outputs( - reservoir, - training_inputs, - NUM_TRAINING_STEPS, - NUM_INPUTS, - NUM_OUTPUTS, - 10, - "Software outputs before training:" - ); - - //training the readout layer - const double lambda = 1.0e-4; - int training_status = train_reservoir(reservoir, training_inputs, - target_outputs, NUM_TRAINING_STEPS, lambda); - if (training_status < 0) { - fprintf(stderr, "Failed to train the reservoir"); - free_reservoir_state_matrix(&state_matrix); - spires_reservoir_destroy(reservoir); - return -1; - } - - print_software_outputs( - reservoir, - training_inputs, - NUM_TRAINING_STEPS, - NUM_INPUTS, - NUM_OUTPUTS, - 10, - "Software outputs after training:" - ); - - //generate raster plot for verification - if (plot_raster(&state_matrix, NUM_NEURONS, SPIKE_THRESHOLD) != 0) { - fprintf(stderr, "Failed to plot raster\n"); - } - - //fill out initial resistances - double *initial_resistances = malloc(NUM_NEURONS * NUM_OUTPUTS * sizeof(*initial_resistances)); - if (!initial_resistances) { - fprintf(stderr, "Failed to allocate memory for initial resistances"); - return -1; - } - - //resistances are inversely proportional to the software weigts - for (size_t i = 0; i < NUM_NEURONS * NUM_OUTPUTS; i++) { - initial_resistances[i] = 80000; - } - - //convert continous states to spikes - double *spikes_voltages = malloc(state_matrix.num_features * - state_matrix.num_samples * sizeof(*spikes_voltages)); - - if (spikes_voltages == NULL) { - fprintf(stderr, "Failed to allocate spikes voltages"); - free(initial_resistances); - free_reservoir_state_matrix(&state_matrix); - spires_reservoir_destroy(reservoir); - return -1; - } - - for (size_t sample = 0; sample < state_matrix.num_samples; sample++) { - for (size_t neuron = 0; neuron < state_matrix.num_features; neuron++) { - size_t index = sample * state_matrix.num_features + neuron; - - spikes_voltages[index] = - state_matrix.states [index] > SPIKE_THRESHOLD ? SPIKE_AMPLITUDE : 0.0; - } - } - - const Crossbar_Config crossbar_config = { - .rows = state_matrix.num_features, - .columns = NUM_OUTPUTS, - .input_series = spikes_voltages, - .num_samples = state_matrix.num_samples, - .initial_resistance = initial_resistances, - .model_path = "hp_memristor.cir", - .subcircuit_name = "memristor", - .load_resistance = 50.0, - .time_step = 1e-6, - .stop_time = state_matrix.num_samples * 1e-6, - .print_state_nodes = 0 - }; - - if (generate_crossbar("crossbar.cir", &crossbar_config) < 0) { - fprintf(stderr, "failed to create crossbar config"); - free(initial_resistances); - free_reservoir_state_matrix(&state_matrix); - spires_reservoir_destroy(reservoir); - return -1; - } - printf("Generated crossbar!!"); - - //call ngspice for crossbar - if (run_ngspice("crossbar.cir") < 0) { - fprintf(stderr, "Failed to run_ngspice"); - free(initial_resistances); - free_reservoir_state_matrix(&state_matrix); - spires_reservoir_destroy(reservoir); - return -1; - } - printf("ran ngspice!!"); - - //crossbar parameters needed for reading - Crossbar_Output_Matrix crossbar_output = { - .num_samples = NUM_TRAINING_STEPS, //this isnt right? - .num_outputs = NUM_OUTPUTS, - .time = NULL, - .voltages = NULL - }; - - if (read_crossbar("crossbar_output.dat", NUM_OUTPUTS, &crossbar_output) < 0) { - fprintf(stderr, "Failed to read crossbar output file"); - free(initial_resistances); - free_reservoir_state_matrix(&state_matrix); - spires_reservoir_destroy(reservoir); - free_crossbar_output_matrix(&crossbar_output); - return -1; - } - printf("read the crossbar outputs!!"); - - //printing for testing purposes - // printf("Read data:\n"); - // for (size_t sample = 0; sample < crossbar_output.num_samples; sample++) { - // printf("%f", crossbar_output.time[sample]); - // for (size_t output = 0; output < crossbar_output.num_outputs; output++) { - // printf(" %f", - // crossbar_output.voltages[sample * crossbar_output.num_outputs + output]); - // } - // printf("\n"); - // } - - printf("YAY IT WORKED!!! Cleaning up :)"); - free(initial_resistances); - free(spikes_voltages); - free_reservoir_state_matrix(&state_matrix); - spires_reservoir_destroy(reservoir); - free_crossbar_output_matrix(&crossbar_output); - - return 0; -} +static int plot_raster(const Reservoir_State_Matrix *matrix, + size_t neurons_to_plot, double spike_threshold); -static int plot_raster( - const Reservoir_State_Matrix *matrix, - size_t neurons_to_plot, - double spike_threshold -) { - if (!matrix || !matrix->states || matrix->num_samples == 0) { - return -1; - } - - if (neurons_to_plot > matrix->num_features) { - neurons_to_plot = matrix->num_features; - } - - //count spikes - size_t spike_count = 0; - for (size_t t = 0; t < matrix->num_samples; t++) { - for (size_t n = 0; n < neurons_to_plot; n++) { - double value = matrix->states[t * matrix->num_features + n]; - if (value > spike_threshold) { - spike_count++; - } - } - } - - if (spike_count == 0) { - fprintf(stderr, "No spikes found above threshold %.3f\n", spike_threshold); - return -1; - } - - PLFLT *x = malloc(spike_count * sizeof(*x)); - PLFLT *y = malloc(spike_count * sizeof(*y)); - if (!x || !y) { - free(x); - free(y); - return -1; - } - - //fill spike coordinates - size_t k = 0; - for (size_t t = 0; t < matrix->num_samples; t++) { - for (size_t n = 0; n < neurons_to_plot; n++) { - double value = matrix->states[t * matrix->num_features + n]; - if (value > spike_threshold) { - x[k] = (PLFLT)t; - y[k] = (PLFLT)n; - k++; - } - } - } - - //output to png - plsdev("svg"); - plsfnam("reservoir_raster.svg"); - - plsetopt("geometry", "1600x1200"); - plscolbg(255, 255, 255); - - plinit(); - - plscol0(1, 40, 40, 40); //gray axis - plscol0(2, 0, 0, 0); //blue points - - plcol0(1); - plwidth(1.0); - - plenv( - 0.0, - (PLFLT)(matrix->num_samples - 1), - 0.0, - (PLFLT)(neurons_to_plot - 1), - 0, - 0 - ); - - pllab( - "Timestep", - "Neuron index", - "SPIRES Reservoir Raster Plot" - ); - - plcol0(2); - plwidth(1.0); - - for (size_t i = 0; i < spike_count; i++) { - PLFLT xline[2] = {x[i], x[i]}; - PLFLT yline[2] = {y[i] - 0.35, y[i] + 0.35}; - - plline(2, xline, yline); - } - - plend(); - - free(x); - free(y); - return 0; +int main(void) +{ + // discrete LIF parameters for spires + double lif_config[] = { + 0.0, // V_off + 1.0, // V_th + 0.2, // leak rate + 0.5, // bias + }; + + const spires_reservoir_config config = { + .num_neurons = NUM_NEURONS, + .num_inputs = NUM_INPUTS, + .num_outputs = NUM_OUTPUTS, + .spectral_radius = 0.95, + .ei_ratio = 0.8, + .input_strength = 0.1, + .connectivity = 0.1, + .dt = 1.0, + .connectivity_type = SPIRES_CONN_RANDOM, + .neuron_type = SPIRES_NEURON_LIF_DISCRETE, + .neuron_params = lif_config}; + + spires_reservoir *reservoir = NULL; + + spires_status status = spires_reservoir_create(&config, &reservoir); + + if (status != SPIRES_OK) { + fprintf(stderr, "Failed to create reservoir"); + return -1; + } + + // create training inputs + double training_inputs[NUM_TRAINING_STEPS * NUM_INPUTS]; + for (size_t timestep = 0; timestep < NUM_TRAINING_STEPS; timestep++) { + for (size_t input = 0; input < NUM_INPUTS; input++) { + training_inputs[timestep * NUM_INPUTS + input] = + sin(2.0 * PI * (double)timestep / 50.0); + } + } + + // create target outputs + double target_outputs[NUM_TRAINING_STEPS * NUM_OUTPUTS]; + for (size_t timestep = 0; timestep < NUM_TRAINING_STEPS; timestep++) { + size_t next_timestep = (timestep + 1) % NUM_TRAINING_STEPS; + double target = sin(2.0 * PI * (double)next_timestep / 50.0); + for (size_t output = 0; output < NUM_OUTPUTS; output++) { + target_outputs[timestep * NUM_OUTPUTS + output] = + target; + } + } + + Reservoir_State_Matrix state_matrix = {0}; + if (collect_reservoir_states(reservoir, training_inputs, + NUM_TRAINING_STEPS, &state_matrix) != 0) { + fprintf(stderr, "Failed to collect reservoir states"); + spires_reservoir_destroy(reservoir); + return -1; + } + printf("collected state matrix: %zu x %zu\n", state_matrix.num_samples, + state_matrix.num_features); + + // training the readout layer + const double lambda = 1.0e-4; + int training_status = + train_reservoir(reservoir, training_inputs, target_outputs, + NUM_TRAINING_STEPS, lambda); + if (training_status < 0) { + fprintf(stderr, "Failed to train the reservoir"); + free_reservoir_state_matrix(&state_matrix); + spires_reservoir_destroy(reservoir); + return -1; + } + + // generate raster plot for verification + if (plot_raster(&state_matrix, NUM_NEURONS, SPIKE_THRESHOLD) != 0) { + fprintf(stderr, "Failed to plot raster\n"); + } + + // copy readout weights and convert to conductances + double *initial_resistances = NULL; + conductance_mapping mapping; + + if (convert_weights_to_resistances( + reservoir, NUM_NEURONS, NUM_OUTPUTS, 1000.0, 100000.0, + &initial_resistances, &mapping) != 0) { + return -1; + } + + double *row_voltages = + malloc(state_matrix.num_features * state_matrix.num_samples * + sizeof(double)); + + if (row_voltages == NULL) { + fprintf(stderr, "Failed to allocate spikes voltages"); + free(initial_resistances); + free_reservoir_state_matrix(&state_matrix); + spires_reservoir_destroy(reservoir); + return -1; + } + + for (size_t sample = 0; sample < state_matrix.num_samples; sample++) { + for (size_t neuron = 0; neuron < state_matrix.num_features; + neuron++) { + size_t index = + sample * state_matrix.num_features + neuron; + + row_voltages[index] = + SPIKE_AMPLITUDE * state_matrix.states[index]; + } + } + + const Crossbar_Config crossbar_config = { + .rows = state_matrix.num_features, + .columns = NUM_CROSSBAR_COLUMNS, + .input_series = row_voltages, + .num_samples = state_matrix.num_samples, + .initial_resistance = initial_resistances, + .model_path = "hp_memristor.cir", + .subcircuit_name = "memristor", + .load_resistance = 50.0, + .time_step = 1e-6, + .stop_time = state_matrix.num_samples * 1e-6, + .print_state_nodes = 0}; + + if (generate_crossbar("crossbar.cir", &crossbar_config) < 0) { + fprintf(stderr, "failed to create crossbar config"); + free(initial_resistances); + free_reservoir_state_matrix(&state_matrix); + spires_reservoir_destroy(reservoir); + return -1; + } + printf("Generated crossbar!!"); + + // call ngspice for crossbar + if (run_ngspice("crossbar.cir") < 0) { + fprintf(stderr, "Failed to run_ngspice"); + free(initial_resistances); + free_reservoir_state_matrix(&state_matrix); + spires_reservoir_destroy(reservoir); + return -1; + } + printf("ran ngspice!!"); + + // crossbar parameters needed for reading + Crossbar_Output_Matrix crossbar_output = { + .num_samples = NUM_TRAINING_STEPS, + .num_outputs = NUM_CROSSBAR_COLUMNS, + .time = NULL, + .voltages = NULL}; + + if (read_crossbar("crossbar_output.dat", NUM_CROSSBAR_COLUMNS, + &crossbar_output) < 0) { + fprintf(stderr, "Failed to read crossbar output file"); + free(initial_resistances); + free_reservoir_state_matrix(&state_matrix); + spires_reservoir_destroy(reservoir); + free_crossbar_output_matrix(&crossbar_output); + return -1; + } + printf("read the crossbar outputs!!\n"); + + double *decoded_outputs = + malloc(NUM_OUTPUTS * NUM_TRAINING_STEPS * sizeof(double)); + if (decoded_outputs == NULL) { + fprintf(stderr, + "Failed to allocate memory for decoded outputs"); + } + if (convert_output_to_software( + NUM_NEURONS, NUM_OUTPUTS, NUM_TRAINING_STEPS, + crossbar_output.voltages, initial_resistances, + crossbar_config.load_resistance, &mapping, row_voltages, + SPIKE_AMPLITUDE, decoded_outputs) < 0) { + fprintf(stderr, + "Failed to convert crossbar outputs back to software"); + return -1; + } + + // comparing prediction + for (int i = 0; i < NUM_TRAINING_STEPS; i++) { + printf("real: %g , predicted: %g\n", target_outputs[i], + decoded_outputs[i]); + } + + printf("YAY IT WORKED!!! Cleaning up :)"); + free(initial_resistances); + // free(spikes_voltages); + free(row_voltages); + free(decoded_outputs); + free_reservoir_state_matrix(&state_matrix); + spires_reservoir_destroy(reservoir); + free_crossbar_output_matrix(&crossbar_output); + + return 0; } -static int print_software_outputs( - spires_reservoir *reservoir, - const double *input_series, - size_t series_length, - size_t num_inputs, - size_t num_outputs, - size_t samples_to_print, - const char *label -) +static int plot_raster(const Reservoir_State_Matrix *matrix, + size_t neurons_to_plot, double spike_threshold) { - if (!reservoir || !input_series || !label) { - return -1; - } - - double *output = malloc(num_outputs * sizeof(*output)); - if (!output) { - return -1; - } - - if (spires_reservoir_reset(reservoir) != SPIRES_OK) { - free(output); - return -1; - } - - if (samples_to_print > series_length) { - samples_to_print = series_length; - } - - printf("\n%s\n", label); - - for (size_t timestep = 0; - timestep < series_length; - timestep++) { - - const double *current_input = - &input_series[timestep * num_inputs]; - - if (spires_step(reservoir, current_input) != SPIRES_OK) { - free(output); - return -1; - } - - if (spires_compute_output(reservoir, output) != SPIRES_OK) { - free(output); - return -1; - } - - if (timestep < samples_to_print) { - printf("timestep %zu:", timestep); - - for (size_t output_index = 0; - output_index < num_outputs; - output_index++) { - - printf( - " output[%zu]=%+.8e", - output_index, - output[output_index] - ); - } - - printf("\n"); - } - } - - free(output); - return 0; + if (!matrix || !matrix->states || matrix->num_samples == 0) { + return -1; + } + + if (neurons_to_plot > matrix->num_features) { + neurons_to_plot = matrix->num_features; + } + + // count spikes + size_t spike_count = 0; + for (size_t t = 0; t < matrix->num_samples; t++) { + for (size_t n = 0; n < neurons_to_plot; n++) { + double value = + matrix->states[t * matrix->num_features + n]; + if (value > spike_threshold) { + spike_count++; + } + } + } + + if (spike_count == 0) { + fprintf(stderr, "No spikes found above threshold %.3f\n", + spike_threshold); + return -1; + } + + PLFLT *x = malloc(spike_count * sizeof(*x)); + PLFLT *y = malloc(spike_count * sizeof(*y)); + if (!x || !y) { + free(x); + free(y); + return -1; + } + + // fill spike coordinates + size_t k = 0; + for (size_t t = 0; t < matrix->num_samples; t++) { + for (size_t n = 0; n < neurons_to_plot; n++) { + double value = + matrix->states[t * matrix->num_features + n]; + if (value > spike_threshold) { + x[k] = (PLFLT)t; + y[k] = (PLFLT)n; + k++; + } + } + } + + // output to png + plsdev("svg"); + plsfnam("reservoir_raster.svg"); + + plsetopt("geometry", "1600x1200"); + plscolbg(255, 255, 255); + + plinit(); + + plscol0(1, 40, 40, 40); // gray axis + plscol0(2, 0, 0, 0); // blue points + + plcol0(1); + plwidth(1.0); + + plenv(0.0, (PLFLT)(matrix->num_samples - 1), 0.0, + (PLFLT)(neurons_to_plot - 1), 0, 0); + + pllab("Timestep", "Neuron index", "SPIRES Reservoir Raster Plot"); + + plcol0(2); + plwidth(1.0); + + for (size_t i = 0; i < spike_count; i++) { + PLFLT xline[2] = {x[i], x[i]}; + PLFLT yline[2] = {y[i] - 0.35, y[i] + 0.35}; + + plline(2, xline, yline); + } + + plend(); + + free(x); + free(y); + return 0; } diff --git a/src/main.o b/src/main.o deleted file mode 100644 index 392a241..0000000 Binary files a/src/main.o and /dev/null differ diff --git a/src/makefile b/src/makefile index bb501b5..9603d7d 100644 --- a/src/makefile +++ b/src/makefile @@ -4,7 +4,7 @@ TARGET := main SPIRES_DIR := ../spires SOURCES := main.c spires_interface.c crossbar_generator.c read_crossbar.c -OBJECTS := $(SOURCES:.c=.o) +OBJECTS := $(SOURCES:.c=.a) PLPLOT_LIBS := $(shell pkg-config --libs plplot) @@ -23,7 +23,7 @@ all: $(TARGET) $(TARGET): $(OBJECTS) $(CC) $(OBJECTS) $(LDFLAGS) $(LDLIBS) -o $(TARGET) -%.o: %.c +%.a: %.c $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ run: $(TARGET) diff --git a/src/read_crossbar.a b/src/read_crossbar.a new file mode 100644 index 0000000..8e36677 Binary files /dev/null and b/src/read_crossbar.a differ diff --git a/src/read_crossbar.c b/src/read_crossbar.c index 3666d53..b075c69 100644 --- a/src/read_crossbar.c +++ b/src/read_crossbar.c @@ -3,6 +3,7 @@ #include #include //maybe I could use this #include +#include #include #include #include @@ -10,123 +11,229 @@ #include #include -int run_ngspice(const char *crossbar_path) { - if (crossbar_path == NULL) { - fprintf(stderr, "One of the file paths returned null when running ngspice"); - return -1; - } - - char command[4096]; - int written = snprintf(command, sizeof(command), - "ngspice -b \"%s\" > /dev/null 2>&1", crossbar_path); - - if (written < 0) { - fprintf(stderr, "Failed to write spice command"); - return -1; - } - - int status = system(command); - if (status < 0) { - fprintf(stderr, "Failed to run ngspice command"); - } - - return 0; +int run_ngspice(const char *crossbar_path) +{ + if (crossbar_path == NULL) { + fprintf( + stderr, + "One of the file paths returned null when running ngspice"); + return -1; + } + + char command[4096]; + int written = + snprintf(command, sizeof(command), + "ngspice -b \"%s\" > /dev/null 2>&1", crossbar_path); + + if (written < 0) { + fprintf(stderr, "Failed to write spice command"); + return -1; + } + + int status = system(command); + if (status < 0) { + fprintf(stderr, "Failed to run ngspice command"); + } + + return 0; } int read_crossbar(const char *data_path, size_t num_outputs, - Crossbar_Output_Matrix *result) { - - FILE *file = fopen(data_path, "r"); - if (!file){ - fprintf(stderr, "Faile to open data file"); - return -1; - } - - result->num_samples = 0; - result->num_outputs = num_outputs; - result->time = NULL; - result->voltages = NULL; - - size_t capacity = 100000; - - result->time = malloc(capacity * sizeof(*result->time)); - result->voltages = malloc(capacity * num_outputs * sizeof(*result->voltages)); - - if (result->time == NULL || result->voltages == NULL) { - fprintf(stderr, "Failed to allocate memory for results"); - fclose(file); - free_crossbar_output_matrix(result); - return -1; - } - - size_t expected_fields = num_outputs * 2; - double *fields = malloc(expected_fields * sizeof(*fields)); - if (fields == NULL) { - fprintf(stderr, "failed to allocate memory for fields"); - fclose(file); - free_crossbar_output_matrix(result); - return -1; - } - - char line[16384]; - // size_t line_number = 0; - - while(fgets(line, sizeof(line), file) != NULL) { - /* Raises capacity if needed, not working rn tho */ - // if (result->num_samples == capacity) { - // capacity *= 2; - // - // result->time = realloc(result->time, capacity * sizeof(double)); - // result->voltages = realloc(result->voltages, capacity * sizeof(double)); - // - // if (result->time == NULL || result->voltages == NULL) { - // fprintf(stderr, "Failed to reallocate memory"); - // fclose(file); - // return -1; - // } - // } - - char *position = line; - double sample_time = 0.0; - - //each loop reads one time-voltage pair, saves it - //then moves to next loop (next time-voltage pair) - for (size_t output = 0; output < num_outputs; output++) { - double time; - double voltage; - int char_count; - - if(sscanf(position, "%lf %lf %n", &time, &voltage, &char_count) != 2) { - fprintf(stderr, "invalide data line"); - fclose(file); - return -1; - } - - if (output == 0) { - sample_time = time; - } - - result->voltages[result->num_samples * num_outputs + output] = voltage; - position += char_count; - - } - result->time[result->num_samples] = sample_time; - result->num_samples++; - } - fclose(file); - return 0; + Crossbar_Output_Matrix *result) +{ + + FILE *file = fopen(data_path, "r"); + if (!file) { + fprintf(stderr, "Faile to open data file"); + return -1; + } + + result->num_samples = 0; + result->num_outputs = num_outputs; + result->time = NULL; + result->voltages = NULL; + + size_t capacity = 100000; + + result->time = malloc(capacity * sizeof(*result->time)); + result->voltages = + malloc(capacity * num_outputs * sizeof(*result->voltages)); + + if (result->time == NULL || result->voltages == NULL) { + fprintf(stderr, "Failed to allocate memory for results"); + fclose(file); + free_crossbar_output_matrix(result); + return -1; + } + + size_t expected_fields = num_outputs * 2; + double *fields = malloc(expected_fields * sizeof(*fields)); + if (fields == NULL) { + fprintf(stderr, "failed to allocate memory for fields"); + fclose(file); + free_crossbar_output_matrix(result); + return -1; + } + + char line[16384]; + // size_t line_number = 0; + + while (fgets(line, sizeof(line), file) != NULL) { + /* Raises capacity if needed, not working rn tho */ + // if (result->num_samples == capacity) { + // capacity *= 2; + // + // result->time = realloc(result->time, capacity * + // sizeof(double)); result->voltages = + // realloc(result->voltages, capacity * sizeof(double)); + // + // if (result->time == NULL || result->voltages == NULL) { + // fprintf(stderr, "Failed to reallocate memory"); + // fclose(file); + // return -1; + // } + // } + + char *position = line; + double sample_time = 0.0; + + // each loop reads one time-voltage pair, saves it + // then moves to next loop (next time-voltage pair) + for (size_t output = 0; output < num_outputs; output++) { + double time; + double voltage; + int char_count; + + if (sscanf(position, "%lf %lf %n", &time, &voltage, + &char_count) != 2) { + fprintf(stderr, "invalide data line"); + fclose(file); + return -1; + } + + if (output == 0) { + sample_time = time; + } + + result->voltages[result->num_samples * num_outputs + + output] = voltage; + position += char_count; + } + result->time[result->num_samples] = sample_time; + result->num_samples++; + } + fclose(file); + return 0; } -void free_crossbar_output_matrix(Crossbar_Output_Matrix *result) { - if (result == NULL) { - return; - } +int convert_output_to_software(size_t num_neurons, size_t num_outputs, + size_t num_timesteps, const double *voltages, + const double *resistances, + double load_resistance, + const conductance_mapping *mapping, + const double *row_voltages, + double spike_amplitude, double *decoded_outputs) +{ + // Using differential pair mapping + size_t num_physical_columns; + + if (!voltages || !resistances || !mapping || !decoded_outputs) + return -1; + + if (load_resistance <= 0.0 || mapping->alpha == 0.0 || + spike_amplitude == 0.0) + return -1; + + num_physical_columns = num_outputs * 2; + + for (size_t timestep = 0; timestep < num_timesteps; timestep++) { + for (size_t output = 0; output < num_outputs; output++) { + size_t positive_column; + size_t negative_column; + size_t positive_voltage_index; + size_t negative_voltage_index; + size_t output_index; + double positive_conductance_sum = 0.0; + double negative_conductance_sum = 0.0; + double positive_voltage; + double negative_voltage; + double positive_load_current; + double negative_load_current; + double positive_source_current; + double negative_source_current; + + positive_column = 2 * output; + negative_column = positive_column + 1; + + for (size_t neuron = 0; neuron < num_neurons; + neuron++) { + size_t positive_resistance_index; + size_t negative_resistance_index; + + positive_resistance_index = + neuron * num_physical_columns + + positive_column; + + negative_resistance_index = + neuron * num_physical_columns + + negative_column; + + positive_conductance_sum += + 1.0 / + resistances[positive_resistance_index]; + + negative_conductance_sum += + 1.0 / + resistances[negative_resistance_index]; + } + + positive_voltage_index = + timestep * num_physical_columns + positive_column; + + negative_voltage_index = + timestep * num_physical_columns + negative_column; + + positive_voltage = voltages[positive_voltage_index]; + + negative_voltage = voltages[negative_voltage_index]; + + positive_load_current = + positive_voltage / load_resistance; + + negative_load_current = + negative_voltage / load_resistance; + + positive_source_current = + positive_load_current + + positive_voltage * positive_conductance_sum; + + negative_source_current = + negative_load_current + + negative_voltage * negative_conductance_sum; + + output_index = timestep * num_outputs + output; + + decoded_outputs[output_index] = + (positive_source_current - + negative_source_current) / + (mapping->alpha * spike_amplitude); + } + } + + return 0; +} + +void free_crossbar_output_matrix(Crossbar_Output_Matrix *result) +{ + if (result == NULL) { + return; + } - free(result->time); - free(result->voltages); + free(result->time); + free(result->voltages); - result->num_samples = 0; - result->num_outputs = 0; - result->time = NULL; - result->voltages = NULL; + result->num_samples = 0; + result->num_outputs = 0; + result->time = NULL; + result->voltages = NULL; } diff --git a/src/read_crossbar.h b/src/read_crossbar.h index 81aad02..74828d2 100644 --- a/src/read_crossbar.h +++ b/src/read_crossbar.h @@ -1,23 +1,32 @@ #ifndef READ_CROSSBAR_H #define READ_CROSSBAR_H +#include "spires_interface.h" #include typedef struct { - size_t num_samples; //number of time-steps - size_t num_outputs; //number of columns + size_t num_samples; // number of time-steps + size_t num_outputs; // number of columns - double *time; + double *time; - // stored in row major order - // voltages[sameple * num_outputs + output] - double *voltages; + // stored in row major order + // voltages[sameple * num_outputs + output] + double *voltages; } Crossbar_Output_Matrix; int run_ngspice(const char *crossbar_path); -int read_crossbar(const char *data_path, size_t num_outputs, - Crossbar_Output_Matrix *result); +int read_crossbar(const char *data_path, size_t num_outputs, + Crossbar_Output_Matrix *result); + +int convert_output_to_software(size_t num_neurons, size_t num_outputs, + size_t num_timesteps, const double *voltages, + const double *resistances, + double load_resistance, + const conductance_mapping *mapping, + const double *row_voltages, + double spike_amplitude, double *decoded_outputs); void free_crossbar_output_matrix(Crossbar_Output_Matrix *result); diff --git a/src/read_crossbar.o b/src/read_crossbar.o deleted file mode 100644 index 9e85b9f..0000000 Binary files a/src/read_crossbar.o and /dev/null differ diff --git a/src/reservoir_raster.svg b/src/reservoir_raster.svg index f004704..42c8bf7 100644 --- a/src/reservoir_raster.svg +++ b/src/reservoir_raster.svg @@ -296,14 +296,11 @@ - - - @@ -315,7 +312,6 @@ - @@ -345,14 +341,11 @@ - - - @@ -363,14 +356,12 @@ - - @@ -418,21 +409,14 @@ - - - - - - - @@ -451,13 +435,10 @@ - - - @@ -466,12 +447,10 @@ - - @@ -483,48 +462,35 @@ - - - - - - - - - - - - - @@ -552,11 +518,9 @@ - - @@ -569,21 +533,16 @@ - - - - - @@ -591,7 +550,6 @@ - @@ -605,7 +563,6 @@ - @@ -613,7 +570,6 @@ - @@ -627,10 +583,7 @@ - - - @@ -643,14 +596,12 @@ - - @@ -685,63 +636,41 @@ - - - - - - - - - - - - - - - - - - - - - - @@ -749,24 +678,15 @@ - - - - - - - - - @@ -774,23 +694,14 @@ - - - - - - - - - @@ -798,23 +709,14 @@ - - - - - - - - - @@ -822,23 +724,14 @@ - - - - - - - - - @@ -846,23 +739,14 @@ - - - - - - - - - @@ -870,23 +754,15 @@ - - - - - - - - @@ -895,24 +771,16 @@ - - - - - - - - @@ -921,25 +789,16 @@ - - - - - - - - - @@ -954,117 +813,68 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1072,21 +882,16 @@ - - - - - @@ -1098,46 +903,24 @@ - - - - - - - - - - - - - - - - - - - - - - @@ -1145,23 +928,15 @@ - - - - - - - - @@ -1169,33 +944,17 @@ - - - - - - - - - - - - - - - - @@ -1204,736 +963,311 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1941,209 +1275,97 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -2156,360 +1378,192 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -2517,329 +1571,173 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -2848,1010 +1746,420 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -3862,26 +2170,13 @@ - - - - - - - - - - - - - @@ -3892,130 +2187,72 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -4023,20 +2260,11 @@ - - - - - - - - - @@ -4048,25 +2276,12 @@ - - - - - - - - - - - - - @@ -4076,956 +2291,436 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -5033,361 +2728,174 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -5396,24 +2904,14 @@ - - - - - - - - - - @@ -5421,147 +2919,86 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -5569,218 +3006,118 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -5788,1075 +3125,488 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -6868,30 +3618,16 @@ - - - - - - - - - - - - - - @@ -6899,252 +3635,128 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -7152,168 +3764,94 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -7322,735 +3860,319 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -8058,80 +4180,45 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -8142,184 +4229,99 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -8327,304 +4329,175 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -8632,64 +4505,36 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -8698,215 +4543,107 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -8914,423 +4651,166 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -9338,256 +4818,107 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -9596,72 +4927,40 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -9669,72 +4968,44 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -9742,121 +5013,76 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -9864,205 +5090,119 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -10071,323 +5211,167 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -10397,695 +5381,282 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -11093,119 +5664,50 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -11213,464 +5715,257 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -11679,323 +5974,167 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -12005,695 +6144,282 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -12701,119 +6427,50 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -12821,464 +6478,257 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -13287,323 +6737,167 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -13613,695 +6907,282 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -14309,119 +7190,50 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -14429,464 +7241,257 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -14895,323 +7500,167 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -15221,695 +7670,282 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -15917,119 +7953,50 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -16037,173 +8004,88 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/spires_interface.a b/src/spires_interface.a new file mode 100644 index 0000000..a032b90 Binary files /dev/null and b/src/spires_interface.a differ diff --git a/src/spires_interface.c b/src/spires_interface.c index 0d69eba..243a108 100644 --- a/src/spires_interface.c +++ b/src/spires_interface.c @@ -1,190 +1,198 @@ #include "spires_interface.h" #include -#include -#include -#include -#include #include +#include +#include +#include +#include -int collect_reservoir_states( - spires_reservoir *reservoir, - const double *input_series, - size_t series_length, - Reservoir_State_Matrix *result -) { - //error checking - //RIP - - //clear the result first - result->num_samples = 0; - result->num_features = 0; - result->states = NULL; - - const size_t num_inputs = spires_num_inputs(reservoir); - - const size_t num_neurons = spires_num_neurons(reservoir); - - if (series_length > SIZE_MAX / num_neurons || series_length * num_neurons - > SIZE_MAX / sizeof(double)) { - fprintf(stderr, "matrix size overloaded!!"); - return -1; - } - - double *states = malloc(num_neurons * series_length * sizeof(*states)); - if (!states) { - fprintf(stderr, "failed to allocate memory for states"); - return -1; - } - - spires_status status = spires_reservoir_reset(reservoir); - if (status != SPIRES_OK) { - fprintf(stderr, "reservoir reset error"); - free(states); - return -1; - } - - // build state_matrix - for (size_t i = 0; i < series_length; i++) { - const double *current_input = &input_series[i * num_inputs]; - status = spires_step(reservoir, current_input); - if (status != SPIRES_OK){ - free(states); - return -1; - } - - double *current_state = &states[i * num_neurons]; - status = spires_read_reservoir_state(reservoir, current_state); - if (status != SPIRES_OK){ - free(states); - return -1; - } - } - - result->num_samples = series_length; - result->num_features = num_neurons; - result->states = states; - - return 0; +int collect_reservoir_states(spires_reservoir *reservoir, + const double *input_series, size_t series_length, + Reservoir_State_Matrix *result) +{ + // error checking + // RIP + + // clear the result first + result->num_samples = 0; + result->num_features = 0; + result->states = NULL; + + const size_t num_inputs = spires_num_inputs(reservoir); + + const size_t num_neurons = spires_num_neurons(reservoir); + + if (series_length > SIZE_MAX / num_neurons || + series_length * num_neurons > SIZE_MAX / sizeof(double)) { + fprintf(stderr, "matrix size overloaded!!"); + return -1; + } + + double *states = malloc(num_neurons * series_length * sizeof(*states)); + if (!states) { + fprintf(stderr, "failed to allocate memory for states"); + return -1; + } + + spires_status status = spires_reservoir_reset(reservoir); + if (status != SPIRES_OK) { + fprintf(stderr, "reservoir reset error"); + free(states); + return -1; + } + + // build state_matrix + for (size_t i = 0; i < series_length; i++) { + const double *current_input = &input_series[i * num_inputs]; + status = spires_step(reservoir, current_input); + if (status != SPIRES_OK) { + free(states); + return -1; + } + + double *current_state = &states[i * num_neurons]; + status = spires_read_reservoir_state(reservoir, current_state); + if (status != SPIRES_OK) { + free(states); + return -1; + } + } + + result->num_samples = series_length; + result->num_features = num_neurons; + result->states = states; + + return 0; } -int map_signed_weights_to_resistance( - const double *weights, - size_t num_neurons, - size_t num_outputs, - double resistance_on, - double resistance_off, - double *resistances, - double *conductance_offset, - double *conductance_scale - ) { - //safety check arguments - if (weights == NULL || resistances == NULL || num_neurons == 0 || - num_outputs == 0 || resistance_on <= 0 || resistance_off <= resistance_on) { - return -1; - } - - const size_t count = num_neurons * num_outputs; - - const double conductance_max = 1.0 / resistance_on; - const double conductance_min = 1.0 / resistance_off; - - double max_absolute_weight = 0.0; - - for (size_t i = 0; i < count; i++) { - double magnitude = fabs(weights[i]); - - if (magnitude > max_absolute_weight) { - max_absolute_weight = magnitude; - } - } - - const double offset = - 0.5 * (conductance_max + conductance_min); - - if (max_absolute_weight == 0.0) { - for (size_t i = 0; i < count; i++) { - resistances[i] = 1.0 / offset; - } - - if (conductance_offset != NULL) { - *conductance_offset = offset; - } - - if (conductance_scale != NULL) { - *conductance_scale = 0.0; - } - - return 0; - } - - const double scale = - (conductance_max - conductance_min) / - (2.0 * max_absolute_weight); - - for (size_t i = 0; i < count; i++) { - double conductance = - offset + scale * weights[i]; - - /* - * Protect against small floating-point excursions. - */ - if (conductance < conductance_min) { - conductance = conductance_min; - } else if (conductance > conductance_max) { - conductance = conductance_max; - } - - resistances[i] = 1.0 / conductance; - } - - if (conductance_offset != NULL) { - *conductance_offset = offset; - } - - if (conductance_scale != NULL) { - *conductance_scale = scale; - } - - return 0; +int convert_weights_to_resistances(const spires_reservoir *reservoir, + size_t num_neurons, size_t num_outputs, + double r_on, double r_off, + double **resistances_out, + conductance_mapping *mapping) +{ + double *readout; + double *resistances; + double max_abs_weight = 0.0; + size_t weight_count; + size_t weight_index; + size_t positive_index; + size_t negative_index; + size_t positive_column; + size_t negative_column; + double positive_conductance; + double negative_conductance; + + *resistances_out = NULL; + weight_count = num_neurons * num_outputs; + size_t num_physical_columns = num_outputs * 2; + + readout = spires_copy_readout(reservoir); + + // print readout for debugging + for (size_t i = 0; i < (num_neurons * num_outputs); i++) { + printf("%zu : %g\n", i, readout[i]); + } + + resistances = + malloc(num_neurons * num_physical_columns * sizeof(double)); + if (resistances == NULL) { + fprintf(stderr, "Failed to allocated crossbar resistances"); + free(readout); + return -1; + } + + // get the max weight + for (size_t i = 0; i < weight_count; i++) { + if (!isfinite(readout[i])) { + fprintf(stderr, + "invalid readout weight at index %zu: %g\n", i, + readout[i]); + free(readout); + free(resistances); + return -1; + } + + double abs_weight = fabs(readout[i]); + if (abs_weight > max_abs_weight) { + max_abs_weight = abs_weight; + } + } + printf("max absolute weight = %.12e\n", max_abs_weight); + + mapping->g_min = 1.0 / r_off; + mapping->g_max = 1.0 / r_on; + mapping->max_abs_weight = max_abs_weight; + + // calculate the alpha scaling parameter to normalize the weights + mapping->alpha = (mapping->g_max - mapping->g_min) / max_abs_weight; + + // differential pair mapping + for (size_t neuron = 0; neuron < num_neurons; neuron++) { + for (size_t output = 0; output < num_outputs; output++) { + weight_index = output * num_neurons + neuron; + positive_column = 2 * output; + negative_column = positive_column + 1; + + positive_index = + neuron * num_physical_columns + positive_column; + negative_index = + neuron * num_physical_columns + negative_column; + + double weight = readout[weight_index]; + if (weight >= 0.0) { + positive_conductance = + mapping->g_min + mapping->alpha * weight; + negative_conductance = mapping->g_min; + } + if (weight < 0.0) { + positive_conductance = mapping->g_min; + negative_conductance = + mapping->g_min + mapping->alpha * (-weight); + } + + resistances[positive_index] = + 1.0 / positive_conductance; + resistances[negative_index] = + 1.0 / negative_conductance; + } + } + printf("max absolute weight = %.12e\n", mapping->max_abs_weight); + printf("alpha = %.12e\n", mapping->alpha); + printf("physical crossbar dimensions: %zu x %zu\n", num_neurons, + num_physical_columns); + + *resistances_out = resistances; + free(readout); + + return 0; } -int train_reservoir( - spires_reservoir *reservoir, - double *input_series, - double *target_series, - size_t series_length, - double lambda -) { - spires_status status = spires_train_ridge( - reservoir, - (double *)input_series, - (double *)target_series, - series_length, - lambda - ); - - if (status != SPIRES_OK) { - fprintf(stderr, "Spires ridge training failed"); - return -1; - } - //need to figure out how to scale weights to conductance values, - - //that are then the reciprocal of the resistances - - //Also need to find some conversion for output column current, and target_series - return 0; +int train_reservoir(spires_reservoir *reservoir, double *input_series, + double *target_series, size_t series_length, double lambda) +{ + spires_status status = + spires_train_ridge(reservoir, (double *)input_series, + (double *)target_series, series_length, lambda); + + if (status != SPIRES_OK) { + fprintf(stderr, "Spires ridge training failed"); + return -1; + } + return 0; } -void free_reservoir_state_matrix(Reservoir_State_Matrix *matrix) { - if (!matrix) { - return; - } +void free_reservoir_state_matrix(Reservoir_State_Matrix *matrix) +{ + if (!matrix) { + return; + } - free(matrix->states); + free(matrix->states); - matrix->states = NULL; - matrix->num_samples = 0; - matrix->num_features = 0; + matrix->states = NULL; + matrix->num_samples = 0; + matrix->num_features = 0; } diff --git a/src/spires_interface.h b/src/spires_interface.h index ebf4b76..006b9d7 100644 --- a/src/spires_interface.h +++ b/src/spires_interface.h @@ -1,43 +1,35 @@ -#ifndef SPIRES_BACKEND_H -#define SPIRES_BACKEND_H +#ifndef SPIRES_INTERFACE_H +#define SPIRES_INTERFACE_H -#include #include +#include typedef struct { - size_t num_samples; //number of time steps - size_t num_features; - double *states; + size_t num_samples; // number of time steps + size_t num_features; + double *states; } Reservoir_State_Matrix; -int collect_reservoir_states( - spires_reservoir *reservoir, - const double *input_series, - size_t series_length, - Reservoir_State_Matrix *result -); - -int map_signed_weights_to_resistance( - const double *weights, - size_t num_neurons, - size_t num_outputs, - double resistance_on, - double resistance_off, - double *resistances, - double *conductance_offset, - double *conductance_scale -); - -int train_reservoir( - spires_reservoir *reservoir, - double *input_series, - double *taret_series, - size_t series_length, - double lambda -); - -void free_reservoir_state_matrix( - Reservoir_State_Matrix *matrix -); +typedef struct { + double g_min; + double g_max; + double alpha; + double max_abs_weight; +} conductance_mapping; + +int collect_reservoir_states(spires_reservoir *reservoir, + const double *input_series, size_t series_length, + Reservoir_State_Matrix *result); + +int train_reservoir(spires_reservoir *reservoir, double *input_series, + double *taret_series, size_t series_length, double lambda); + +int convert_weights_to_resistances(const spires_reservoir *reservoir, + size_t num_neurons, size_t num_outputs, + double r_on, double r_off, + double **resistances_out, + conductance_mapping *mapping); + +void free_reservoir_state_matrix(Reservoir_State_Matrix *matrix); #endif diff --git a/src/spires_interface.o b/src/spires_interface.o deleted file mode 100644 index 2cb9b26..0000000 Binary files a/src/spires_interface.o and /dev/null differ -- cgit v1.2.3