From 3b006a76a3bdfda9ef843694059deed4c507939b Mon Sep 17 00:00:00 2001 From: Garandel Date: Wed, 28 Jul 2021 11:23:11 +0000 Subject: [PATCH 01/44] add meanfield model to spynnaker --- neural_modelling/makefiles/meanfield/Makefile | 22 + .../makefiles/meanfield/meanfield_build.mk | 372 +++++++++++ .../meanfield/meanfield_model_cond/Makefile | 13 + .../makefiles/meanfield/spynnaker.cfg | 8 + .../makefiles/meanfield/untitled.txt | 11 + .../makefiles/meanfield_fixing/.spynnaker.cfg | 3 + .../makefiles/meanfield_fixing/Makefile | 22 + .../meanfield_fixing/meanfield_build.mk | 379 +++++++++++ .../meanfield_model_cond_fixing/Makefile | 15 + .../makefiles/meanfield_fixing/untitled.txt | 11 + .../additional_inputs/additional_input.h | 49 ++ .../additional_input_none_impl.h | 50 ++ .../additional_inputs/my_additional_input.h | 35 + neural_modelling/src/meanfield/c_main.c | 426 +++++++++++++ .../src/meanfield/direct_synapses.c | 70 ++ .../src/meanfield/direct_synapses.h | 37 ++ .../implementations/meanfield_impl.h | 76 +++ .../implementations/meanfield_impl_standard.h | 479 ++++++++++++++ .../implementations/my_full_neuron_impl.h | 116 ++++ .../implementations/my_neuron_impl_semd.h | 281 ++++++++ .../src/meanfield/input_types/input_type.h | 83 +++ .../input_types/input_type_conductance.h | 80 +++ .../input_types/input_type_current.h | 74 +++ .../meanfield/input_types/input_type_delta.h | 78 +++ .../meanfield/input_types/input_type_none.h | 78 +++ .../src/meanfield/input_types/my_input_type.h | 65 ++ neural_modelling/src/meanfield/meanfield.c | 233 +++++++ neural_modelling/src/meanfield/meanfield.h | 99 +++ .../src/meanfield/meanfield_recording.c | 337 ++++++++++ .../src/meanfield/meanfield_recording.h | 228 +++++++ .../src/meanfield/models/config.h | 73 +++ .../src/meanfield/models/mathsbox.h | 23 + .../src/meanfield/models/meanfield_model.h | 105 +++ .../meanfield/models/meanfield_model_impl.c | 346 ++++++++++ .../meanfield/models/meanfield_model_impl.h | 61 ++ .../meanfield/models/my_neuron_model_impl.c | 70 ++ .../meanfield/models/my_neuron_model_impl.h | 28 + .../src/meanfield/plasticity/stdp/maths.h | 143 +++++ .../meanfield/plasticity/stdp/post_events.h | 216 +++++++ .../meanfield/plasticity/stdp/stdp_typedefs.h | 41 ++ .../synapse_structure/synapse_structure.h | 68 ++ ...ynapse_structure_weight_accumulator_impl.h | 120 ++++ .../synapse_structure_weight_impl.h | 93 +++ ..._structure_weight_state_accumulator_impl.h | 123 ++++ ...ure_weight_state_accumulator_window_impl.h | 125 ++++ .../stdp/timing_dependence/my_timing_impl.c | 32 + .../stdp/timing_dependence/my_timing_impl.h | 128 ++++ .../stdp/timing_dependence/timing.h | 80 +++ .../timing_nearest_pair_impl.h | 148 +++++ .../stdp/weight_dependence/my_weight_impl.c | 36 ++ .../stdp/weight_dependence/my_weight_impl.h | 108 ++++ .../stdp/weight_dependence/weight.h | 69 ++ .../weight_additive_one_term_impl.c | 70 ++ .../weight_additive_one_term_impl.h | 128 ++++ .../stdp/weight_dependence/weight_one_term.h | 39 ++ .../meanfield/plasticity/synapse_dynamics.h | 123 ++++ .../plasticity/synapse_dynamics_static_impl.c | 172 +++++ .../population_table/population_table.h | 79 +++ .../population_table_binary_search_impl.c | 592 +++++++++++++++++ neural_modelling/src/meanfield/profile_tags.h | 29 + neural_modelling/src/meanfield/regions.h | 42 ++ .../src/meanfield/spike_processing.c | 521 +++++++++++++++ .../src/meanfield/spike_processing.h | 77 +++ .../synaptogenesis/elimination/elimination.h | 45 ++ .../elimination_random_by_weight_impl.c | 36 ++ .../elimination_random_by_weight_impl.h | 63 ++ .../synaptogenesis/formation/formation.h | 47 ++ .../formation_distance_dependent_impl.c | 41 ++ .../formation_distance_dependent_impl.h | 141 +++++ .../last_neuron_selection_impl.c | 42 ++ .../last_neuron_selection_impl.h | 82 +++ .../partner_selection/partner.h | 64 ++ .../partner_selection/random_selection_impl.c | 23 + .../partner_selection/random_selection_impl.h | 82 +++ .../synaptogenesis/sp_structs.h | 295 +++++++++ .../synaptogenesis/topographic_map_impl.c | 328 ++++++++++ .../synaptogenesis_dynamics.h | 74 +++ .../synaptogenesis_dynamics_static_impl.c | 54 ++ neural_modelling/src/meanfield/synapse_row.h | 243 +++++++ .../meanfield/synapse_types/synapse_types.h | 89 +++ .../synapse_types/synapse_types_alpha_impl.h | 203 ++++++ .../synapse_types/synapse_types_delta_impl.h | 181 ++++++ ...e_types_dual_excitatory_exponential_impl.h | 201 ++++++ .../synapse_types_exponential_impl.h | 188 ++++++ .../synapse_types/synapse_types_my_impl.h | 161 +++++ .../synapse_types/synapse_types_semd_impl.h | 216 +++++++ neural_modelling/src/meanfield/synapses.c | 400 ++++++++++++ neural_modelling/src/meanfield/synapses.h | 130 ++++ .../threshold_types/my_threshold_type.h | 23 + .../threshold_types/threshold_type.h | 41 ++ .../threshold_type_maass_stochastic.h | 70 ++ .../threshold_types/threshold_type_none.h | 37 ++ .../threshold_types/threshold_type_static.h | 40 ++ .../additional_inputs/additional_input.h | 49 ++ .../additional_input_none_impl.h | 50 ++ .../additional_inputs/my_additional_input.h | 35 + .../src/meanfield_fixing/c_main.c | 426 +++++++++++++ .../src/meanfield_fixing/direct_synapses.c | 70 ++ .../src/meanfield_fixing/direct_synapses.h | 37 ++ .../implementations/meanfield_impl.h | 76 +++ .../implementations/meanfield_impl_standard.h | 509 +++++++++++++++ .../implementations/my_full_neuron_impl.h | 116 ++++ .../implementations/my_neuron_impl_semd.h | 281 ++++++++ .../meanfield_fixing/input_types/input_type.h | 83 +++ .../input_types/input_type_conductance.h | 80 +++ .../input_types/input_type_current.h | 74 +++ .../input_types/input_type_delta.h | 78 +++ .../input_types/input_type_none.h | 78 +++ .../input_types/my_input_type.h | 65 ++ .../src/meanfield_fixing/meanfield.c | 233 +++++++ .../src/meanfield_fixing/meanfield.h | 99 +++ .../meanfield_fixing/meanfield_recording.c | 337 ++++++++++ .../meanfield_fixing/meanfield_recording.h | 228 +++++++ .../src/meanfield_fixing/models/config.h | 73 +++ .../src/meanfield_fixing/models/mathsbox.h | 23 + .../meanfield_fixing/models/meanfield_model.h | 105 +++ .../models/meanfield_model_impl.c | 440 +++++++++++++ .../models/meanfield_model_impl.h | 61 ++ .../models/my_neuron_model_impl.c | 70 ++ .../models/my_neuron_model_impl.h | 28 + .../meanfield_fixing/plasticity/stdp/maths.h | 143 +++++ .../plasticity/stdp/post_events.h | 216 +++++++ .../plasticity/stdp/stdp_typedefs.h | 41 ++ .../synapse_structure/synapse_structure.h | 68 ++ ...ynapse_structure_weight_accumulator_impl.h | 120 ++++ .../synapse_structure_weight_impl.h | 93 +++ ..._structure_weight_state_accumulator_impl.h | 123 ++++ ...ure_weight_state_accumulator_window_impl.h | 125 ++++ .../stdp/timing_dependence/my_timing_impl.c | 32 + .../stdp/timing_dependence/my_timing_impl.h | 128 ++++ .../stdp/timing_dependence/timing.h | 80 +++ .../timing_nearest_pair_impl.h | 148 +++++ .../stdp/weight_dependence/my_weight_impl.c | 36 ++ .../stdp/weight_dependence/my_weight_impl.h | 108 ++++ .../stdp/weight_dependence/weight.h | 69 ++ .../weight_additive_one_term_impl.c | 70 ++ .../weight_additive_one_term_impl.h | 128 ++++ .../stdp/weight_dependence/weight_one_term.h | 39 ++ .../plasticity/synapse_dynamics.h | 123 ++++ .../plasticity/synapse_dynamics_static_impl.c | 172 +++++ .../population_table/population_table.h | 79 +++ .../population_table_binary_search_impl.c | 592 +++++++++++++++++ .../src/meanfield_fixing/profile_tags.h | 29 + .../src/meanfield_fixing/regions.h | 42 ++ .../src/meanfield_fixing/spike_processing.c | 521 +++++++++++++++ .../src/meanfield_fixing/spike_processing.h | 77 +++ .../synaptogenesis/elimination/elimination.h | 45 ++ .../elimination_random_by_weight_impl.c | 36 ++ .../elimination_random_by_weight_impl.h | 63 ++ .../synaptogenesis/formation/formation.h | 47 ++ .../formation_distance_dependent_impl.c | 41 ++ .../formation_distance_dependent_impl.h | 141 +++++ .../last_neuron_selection_impl.c | 42 ++ .../last_neuron_selection_impl.h | 82 +++ .../partner_selection/partner.h | 64 ++ .../partner_selection/random_selection_impl.c | 23 + .../partner_selection/random_selection_impl.h | 82 +++ .../synaptogenesis/sp_structs.h | 295 +++++++++ .../synaptogenesis/topographic_map_impl.c | 328 ++++++++++ .../synaptogenesis_dynamics.h | 74 +++ .../synaptogenesis_dynamics_static_impl.c | 54 ++ .../src/meanfield_fixing/synapse_row.h | 243 +++++++ .../synapse_types/synapse_types.h | 89 +++ .../synapse_types/synapse_types_alpha_impl.h | 203 ++++++ .../synapse_types/synapse_types_delta_impl.h | 181 ++++++ ...e_types_dual_excitatory_exponential_impl.h | 201 ++++++ .../synapse_types_exponential_impl.h | 188 ++++++ .../synapse_types/synapse_types_my_impl.h | 161 +++++ .../synapse_types/synapse_types_semd_impl.h | 216 +++++++ .../src/meanfield_fixing/synapses.c | 400 ++++++++++++ .../src/meanfield_fixing/synapses.h | 130 ++++ .../threshold_types/my_threshold_type.h | 23 + .../threshold_types/threshold_type.h | 41 ++ .../threshold_type_maass_stochastic.h | 70 ++ .../threshold_types/threshold_type_none.h | 37 ++ .../threshold_types/threshold_type_static.h | 40 ++ spynnaker/pyNN/models/neuron/__init__.py | 5 +- .../abstract_pynn_meanfield_model_standard.py | 65 ++ .../pyNN/models/neuron/builds/__init__.py | 4 +- .../models/neuron/builds/if_cond_exp_base.py | 3 +- .../models/neuron/builds/meanfield_base.py | 169 +++++ .../models/neuron/implementations/__init__.py | 4 +- .../meanfield_impl_standard.py | 254 ++++++++ .../models/neuron/neuron_models/__init__.py | 6 +- .../neuron_models/abstract_input_type.py | 33 + .../models/neuron/neuron_models/config.py | 598 ++++++++++++++++++ .../models/neuron/neuron_models/mathsbox.py | 123 ++++ .../neuron_models/meanfield_model_eitn.py | 224 +++++++ spynnaker8/__init__.py | 3 + 189 files changed, 23909 insertions(+), 6 deletions(-) create mode 100644 neural_modelling/makefiles/meanfield/Makefile create mode 100644 neural_modelling/makefiles/meanfield/meanfield_build.mk create mode 100644 neural_modelling/makefiles/meanfield/meanfield_model_cond/Makefile create mode 100644 neural_modelling/makefiles/meanfield/spynnaker.cfg create mode 100644 neural_modelling/makefiles/meanfield/untitled.txt create mode 100644 neural_modelling/makefiles/meanfield_fixing/.spynnaker.cfg create mode 100644 neural_modelling/makefiles/meanfield_fixing/Makefile create mode 100644 neural_modelling/makefiles/meanfield_fixing/meanfield_build.mk create mode 100644 neural_modelling/makefiles/meanfield_fixing/meanfield_model_cond_fixing/Makefile create mode 100644 neural_modelling/makefiles/meanfield_fixing/untitled.txt create mode 100644 neural_modelling/src/meanfield/additional_inputs/additional_input.h create mode 100644 neural_modelling/src/meanfield/additional_inputs/additional_input_none_impl.h create mode 100644 neural_modelling/src/meanfield/additional_inputs/my_additional_input.h create mode 100644 neural_modelling/src/meanfield/c_main.c create mode 100644 neural_modelling/src/meanfield/direct_synapses.c create mode 100644 neural_modelling/src/meanfield/direct_synapses.h create mode 100644 neural_modelling/src/meanfield/implementations/meanfield_impl.h create mode 100644 neural_modelling/src/meanfield/implementations/meanfield_impl_standard.h create mode 100644 neural_modelling/src/meanfield/implementations/my_full_neuron_impl.h create mode 100644 neural_modelling/src/meanfield/implementations/my_neuron_impl_semd.h create mode 100644 neural_modelling/src/meanfield/input_types/input_type.h create mode 100644 neural_modelling/src/meanfield/input_types/input_type_conductance.h create mode 100644 neural_modelling/src/meanfield/input_types/input_type_current.h create mode 100644 neural_modelling/src/meanfield/input_types/input_type_delta.h create mode 100644 neural_modelling/src/meanfield/input_types/input_type_none.h create mode 100644 neural_modelling/src/meanfield/input_types/my_input_type.h create mode 100644 neural_modelling/src/meanfield/meanfield.c create mode 100644 neural_modelling/src/meanfield/meanfield.h create mode 100644 neural_modelling/src/meanfield/meanfield_recording.c create mode 100644 neural_modelling/src/meanfield/meanfield_recording.h create mode 100644 neural_modelling/src/meanfield/models/config.h create mode 100644 neural_modelling/src/meanfield/models/mathsbox.h create mode 100644 neural_modelling/src/meanfield/models/meanfield_model.h create mode 100644 neural_modelling/src/meanfield/models/meanfield_model_impl.c create mode 100644 neural_modelling/src/meanfield/models/meanfield_model_impl.h create mode 100644 neural_modelling/src/meanfield/models/my_neuron_model_impl.c create mode 100644 neural_modelling/src/meanfield/models/my_neuron_model_impl.h create mode 100644 neural_modelling/src/meanfield/plasticity/stdp/maths.h create mode 100644 neural_modelling/src/meanfield/plasticity/stdp/post_events.h create mode 100644 neural_modelling/src/meanfield/plasticity/stdp/stdp_typedefs.h create mode 100644 neural_modelling/src/meanfield/plasticity/stdp/synapse_structure/synapse_structure.h create mode 100644 neural_modelling/src/meanfield/plasticity/stdp/synapse_structure/synapse_structure_weight_accumulator_impl.h create mode 100644 neural_modelling/src/meanfield/plasticity/stdp/synapse_structure/synapse_structure_weight_impl.h create mode 100644 neural_modelling/src/meanfield/plasticity/stdp/synapse_structure/synapse_structure_weight_state_accumulator_impl.h create mode 100644 neural_modelling/src/meanfield/plasticity/stdp/synapse_structure/synapse_structure_weight_state_accumulator_window_impl.h create mode 100644 neural_modelling/src/meanfield/plasticity/stdp/timing_dependence/my_timing_impl.c create mode 100644 neural_modelling/src/meanfield/plasticity/stdp/timing_dependence/my_timing_impl.h create mode 100644 neural_modelling/src/meanfield/plasticity/stdp/timing_dependence/timing.h create mode 100644 neural_modelling/src/meanfield/plasticity/stdp/timing_dependence/timing_nearest_pair_impl.h create mode 100644 neural_modelling/src/meanfield/plasticity/stdp/weight_dependence/my_weight_impl.c create mode 100644 neural_modelling/src/meanfield/plasticity/stdp/weight_dependence/my_weight_impl.h create mode 100644 neural_modelling/src/meanfield/plasticity/stdp/weight_dependence/weight.h create mode 100644 neural_modelling/src/meanfield/plasticity/stdp/weight_dependence/weight_additive_one_term_impl.c create mode 100644 neural_modelling/src/meanfield/plasticity/stdp/weight_dependence/weight_additive_one_term_impl.h create mode 100644 neural_modelling/src/meanfield/plasticity/stdp/weight_dependence/weight_one_term.h create mode 100644 neural_modelling/src/meanfield/plasticity/synapse_dynamics.h create mode 100644 neural_modelling/src/meanfield/plasticity/synapse_dynamics_static_impl.c create mode 100644 neural_modelling/src/meanfield/population_table/population_table.h create mode 100644 neural_modelling/src/meanfield/population_table/population_table_binary_search_impl.c create mode 100644 neural_modelling/src/meanfield/profile_tags.h create mode 100644 neural_modelling/src/meanfield/regions.h create mode 100644 neural_modelling/src/meanfield/spike_processing.c create mode 100644 neural_modelling/src/meanfield/spike_processing.h create mode 100644 neural_modelling/src/meanfield/structural_plasticity/synaptogenesis/elimination/elimination.h create mode 100644 neural_modelling/src/meanfield/structural_plasticity/synaptogenesis/elimination/elimination_random_by_weight_impl.c create mode 100644 neural_modelling/src/meanfield/structural_plasticity/synaptogenesis/elimination/elimination_random_by_weight_impl.h create mode 100644 neural_modelling/src/meanfield/structural_plasticity/synaptogenesis/formation/formation.h create mode 100644 neural_modelling/src/meanfield/structural_plasticity/synaptogenesis/formation/formation_distance_dependent_impl.c create mode 100644 neural_modelling/src/meanfield/structural_plasticity/synaptogenesis/formation/formation_distance_dependent_impl.h create mode 100644 neural_modelling/src/meanfield/structural_plasticity/synaptogenesis/partner_selection/last_neuron_selection_impl.c create mode 100644 neural_modelling/src/meanfield/structural_plasticity/synaptogenesis/partner_selection/last_neuron_selection_impl.h create mode 100644 neural_modelling/src/meanfield/structural_plasticity/synaptogenesis/partner_selection/partner.h create mode 100644 neural_modelling/src/meanfield/structural_plasticity/synaptogenesis/partner_selection/random_selection_impl.c create mode 100644 neural_modelling/src/meanfield/structural_plasticity/synaptogenesis/partner_selection/random_selection_impl.h create mode 100644 neural_modelling/src/meanfield/structural_plasticity/synaptogenesis/sp_structs.h create mode 100644 neural_modelling/src/meanfield/structural_plasticity/synaptogenesis/topographic_map_impl.c create mode 100644 neural_modelling/src/meanfield/structural_plasticity/synaptogenesis_dynamics.h create mode 100644 neural_modelling/src/meanfield/structural_plasticity/synaptogenesis_dynamics_static_impl.c create mode 100644 neural_modelling/src/meanfield/synapse_row.h create mode 100644 neural_modelling/src/meanfield/synapse_types/synapse_types.h create mode 100644 neural_modelling/src/meanfield/synapse_types/synapse_types_alpha_impl.h create mode 100644 neural_modelling/src/meanfield/synapse_types/synapse_types_delta_impl.h create mode 100644 neural_modelling/src/meanfield/synapse_types/synapse_types_dual_excitatory_exponential_impl.h create mode 100644 neural_modelling/src/meanfield/synapse_types/synapse_types_exponential_impl.h create mode 100644 neural_modelling/src/meanfield/synapse_types/synapse_types_my_impl.h create mode 100644 neural_modelling/src/meanfield/synapse_types/synapse_types_semd_impl.h create mode 100644 neural_modelling/src/meanfield/synapses.c create mode 100644 neural_modelling/src/meanfield/synapses.h create mode 100644 neural_modelling/src/meanfield/threshold_types/my_threshold_type.h create mode 100644 neural_modelling/src/meanfield/threshold_types/threshold_type.h create mode 100644 neural_modelling/src/meanfield/threshold_types/threshold_type_maass_stochastic.h create mode 100644 neural_modelling/src/meanfield/threshold_types/threshold_type_none.h create mode 100644 neural_modelling/src/meanfield/threshold_types/threshold_type_static.h create mode 100644 neural_modelling/src/meanfield_fixing/additional_inputs/additional_input.h create mode 100644 neural_modelling/src/meanfield_fixing/additional_inputs/additional_input_none_impl.h create mode 100644 neural_modelling/src/meanfield_fixing/additional_inputs/my_additional_input.h create mode 100644 neural_modelling/src/meanfield_fixing/c_main.c create mode 100644 neural_modelling/src/meanfield_fixing/direct_synapses.c create mode 100644 neural_modelling/src/meanfield_fixing/direct_synapses.h create mode 100644 neural_modelling/src/meanfield_fixing/implementations/meanfield_impl.h create mode 100644 neural_modelling/src/meanfield_fixing/implementations/meanfield_impl_standard.h create mode 100644 neural_modelling/src/meanfield_fixing/implementations/my_full_neuron_impl.h create mode 100644 neural_modelling/src/meanfield_fixing/implementations/my_neuron_impl_semd.h create mode 100644 neural_modelling/src/meanfield_fixing/input_types/input_type.h create mode 100644 neural_modelling/src/meanfield_fixing/input_types/input_type_conductance.h create mode 100644 neural_modelling/src/meanfield_fixing/input_types/input_type_current.h create mode 100644 neural_modelling/src/meanfield_fixing/input_types/input_type_delta.h create mode 100644 neural_modelling/src/meanfield_fixing/input_types/input_type_none.h create mode 100644 neural_modelling/src/meanfield_fixing/input_types/my_input_type.h create mode 100644 neural_modelling/src/meanfield_fixing/meanfield.c create mode 100644 neural_modelling/src/meanfield_fixing/meanfield.h create mode 100644 neural_modelling/src/meanfield_fixing/meanfield_recording.c create mode 100644 neural_modelling/src/meanfield_fixing/meanfield_recording.h create mode 100644 neural_modelling/src/meanfield_fixing/models/config.h create mode 100644 neural_modelling/src/meanfield_fixing/models/mathsbox.h create mode 100644 neural_modelling/src/meanfield_fixing/models/meanfield_model.h create mode 100644 neural_modelling/src/meanfield_fixing/models/meanfield_model_impl.c create mode 100644 neural_modelling/src/meanfield_fixing/models/meanfield_model_impl.h create mode 100644 neural_modelling/src/meanfield_fixing/models/my_neuron_model_impl.c create mode 100644 neural_modelling/src/meanfield_fixing/models/my_neuron_model_impl.h create mode 100644 neural_modelling/src/meanfield_fixing/plasticity/stdp/maths.h create mode 100644 neural_modelling/src/meanfield_fixing/plasticity/stdp/post_events.h create mode 100644 neural_modelling/src/meanfield_fixing/plasticity/stdp/stdp_typedefs.h create mode 100644 neural_modelling/src/meanfield_fixing/plasticity/stdp/synapse_structure/synapse_structure.h create mode 100644 neural_modelling/src/meanfield_fixing/plasticity/stdp/synapse_structure/synapse_structure_weight_accumulator_impl.h create mode 100644 neural_modelling/src/meanfield_fixing/plasticity/stdp/synapse_structure/synapse_structure_weight_impl.h create mode 100644 neural_modelling/src/meanfield_fixing/plasticity/stdp/synapse_structure/synapse_structure_weight_state_accumulator_impl.h create mode 100644 neural_modelling/src/meanfield_fixing/plasticity/stdp/synapse_structure/synapse_structure_weight_state_accumulator_window_impl.h create mode 100644 neural_modelling/src/meanfield_fixing/plasticity/stdp/timing_dependence/my_timing_impl.c create mode 100644 neural_modelling/src/meanfield_fixing/plasticity/stdp/timing_dependence/my_timing_impl.h create mode 100644 neural_modelling/src/meanfield_fixing/plasticity/stdp/timing_dependence/timing.h create mode 100644 neural_modelling/src/meanfield_fixing/plasticity/stdp/timing_dependence/timing_nearest_pair_impl.h create mode 100644 neural_modelling/src/meanfield_fixing/plasticity/stdp/weight_dependence/my_weight_impl.c create mode 100644 neural_modelling/src/meanfield_fixing/plasticity/stdp/weight_dependence/my_weight_impl.h create mode 100644 neural_modelling/src/meanfield_fixing/plasticity/stdp/weight_dependence/weight.h create mode 100644 neural_modelling/src/meanfield_fixing/plasticity/stdp/weight_dependence/weight_additive_one_term_impl.c create mode 100644 neural_modelling/src/meanfield_fixing/plasticity/stdp/weight_dependence/weight_additive_one_term_impl.h create mode 100644 neural_modelling/src/meanfield_fixing/plasticity/stdp/weight_dependence/weight_one_term.h create mode 100644 neural_modelling/src/meanfield_fixing/plasticity/synapse_dynamics.h create mode 100644 neural_modelling/src/meanfield_fixing/plasticity/synapse_dynamics_static_impl.c create mode 100644 neural_modelling/src/meanfield_fixing/population_table/population_table.h create mode 100644 neural_modelling/src/meanfield_fixing/population_table/population_table_binary_search_impl.c create mode 100644 neural_modelling/src/meanfield_fixing/profile_tags.h create mode 100644 neural_modelling/src/meanfield_fixing/regions.h create mode 100644 neural_modelling/src/meanfield_fixing/spike_processing.c create mode 100644 neural_modelling/src/meanfield_fixing/spike_processing.h create mode 100644 neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis/elimination/elimination.h create mode 100644 neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis/elimination/elimination_random_by_weight_impl.c create mode 100644 neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis/elimination/elimination_random_by_weight_impl.h create mode 100644 neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis/formation/formation.h create mode 100644 neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis/formation/formation_distance_dependent_impl.c create mode 100644 neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis/formation/formation_distance_dependent_impl.h create mode 100644 neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis/partner_selection/last_neuron_selection_impl.c create mode 100644 neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis/partner_selection/last_neuron_selection_impl.h create mode 100644 neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis/partner_selection/partner.h create mode 100644 neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis/partner_selection/random_selection_impl.c create mode 100644 neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis/partner_selection/random_selection_impl.h create mode 100644 neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis/sp_structs.h create mode 100644 neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis/topographic_map_impl.c create mode 100644 neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis_dynamics.h create mode 100644 neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis_dynamics_static_impl.c create mode 100644 neural_modelling/src/meanfield_fixing/synapse_row.h create mode 100644 neural_modelling/src/meanfield_fixing/synapse_types/synapse_types.h create mode 100644 neural_modelling/src/meanfield_fixing/synapse_types/synapse_types_alpha_impl.h create mode 100644 neural_modelling/src/meanfield_fixing/synapse_types/synapse_types_delta_impl.h create mode 100644 neural_modelling/src/meanfield_fixing/synapse_types/synapse_types_dual_excitatory_exponential_impl.h create mode 100644 neural_modelling/src/meanfield_fixing/synapse_types/synapse_types_exponential_impl.h create mode 100644 neural_modelling/src/meanfield_fixing/synapse_types/synapse_types_my_impl.h create mode 100644 neural_modelling/src/meanfield_fixing/synapse_types/synapse_types_semd_impl.h create mode 100644 neural_modelling/src/meanfield_fixing/synapses.c create mode 100644 neural_modelling/src/meanfield_fixing/synapses.h create mode 100644 neural_modelling/src/meanfield_fixing/threshold_types/my_threshold_type.h create mode 100644 neural_modelling/src/meanfield_fixing/threshold_types/threshold_type.h create mode 100644 neural_modelling/src/meanfield_fixing/threshold_types/threshold_type_maass_stochastic.h create mode 100644 neural_modelling/src/meanfield_fixing/threshold_types/threshold_type_none.h create mode 100644 neural_modelling/src/meanfield_fixing/threshold_types/threshold_type_static.h create mode 100644 spynnaker/pyNN/models/neuron/abstract_pynn_meanfield_model_standard.py create mode 100644 spynnaker/pyNN/models/neuron/builds/meanfield_base.py create mode 100644 spynnaker/pyNN/models/neuron/implementations/meanfield_impl_standard.py create mode 100644 spynnaker/pyNN/models/neuron/neuron_models/abstract_input_type.py create mode 100644 spynnaker/pyNN/models/neuron/neuron_models/config.py create mode 100644 spynnaker/pyNN/models/neuron/neuron_models/mathsbox.py create mode 100644 spynnaker/pyNN/models/neuron/neuron_models/meanfield_model_eitn.py diff --git a/neural_modelling/makefiles/meanfield/Makefile b/neural_modelling/makefiles/meanfield/Makefile new file mode 100644 index 00000000000..6c6586cff24 --- /dev/null +++ b/neural_modelling/makefiles/meanfield/Makefile @@ -0,0 +1,22 @@ +# Copyright (c) 2017-2019 The University of Manchester +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +MODELS = meanfield_model_cond + +all: + for d in $(MODELS); do $(MAKE) -C $$d || exit $$?; done + +clean: + for d in $(MODELS); do $(MAKE) -C $$d clean || exit $$?; done diff --git a/neural_modelling/makefiles/meanfield/meanfield_build.mk b/neural_modelling/makefiles/meanfield/meanfield_build.mk new file mode 100644 index 00000000000..7d7ff6f8da6 --- /dev/null +++ b/neural_modelling/makefiles/meanfield/meanfield_build.mk @@ -0,0 +1,372 @@ +# See Notes in sPyNNaker/neural_modelling/CHANGES_April_2018 + +# Copyright (c) 2017-2019 The University of Manchester +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# If SPINN_DIRS is not defined, this is an error! +ifndef SPINN_DIRS + $(error SPINN_DIRS is not set. Please define SPINN_DIRS (possibly by running "source setup" in the spinnaker package folder)) +endif + +# If NEURAL_MODELLING_DIRS is not defined, this is an error! +ifndef NEURAL_MODELLING_DIRS + $(error NEURAL_MODELLING_DIRS is not set. Please define NEURAL_MODELLING_DIRS (possibly by running "source setup" in the sPyNNaker folder)) +endif +#Check NEURAL_MODELLING_DIRS +MAKEFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +CHECK_PATH := $(NEURAL_MODELLING_DIRS)/makefiles/meanfield/meanfield_build.mk +ifneq ($(CHECK_PATH), $(MAKEFILE_PATH)) + $(error Please check NEURAL_MODELLING_DIRS as based on that this file is at $(CHECK_PATH) when it is actually at $(MAKEFILE_PATH)) +endif + +# Set logging levels +ifeq ($(SPYNNAKER_DEBUG), DEBUG) + NEURON_DEBUG = LOG_DEBUG + SYNAPSE_DEBUG = LOG_DEBUG + PLASTIC_DEBUG = LOG_DEBUG +endif + +ifndef NEURON_DEBUG + NEURON_DEBUG = LOG_INFO +endif + +ifndef SYNAPSE_DEBUG + SYNAPSE_DEBUG = LOG_INFO +endif + +ifndef PLASTIC_DEBUG + PLASTIC_DEBUG = LOG_INFO +endif + +#POPULATION_TABLE_IMPL := fixed +POPULATION_TABLE_IMPL := binary_search + +# Add source directory + +# Define the directories +# Path flag to replace with the modified dir (abspath drops the final /) +MEANFIELD_DIR := $(abspath $(NEURAL_MODELLING_DIRS)/src) +MODIFIED_DIR :=$(dir $(abspath $(MEANFIELD_DIR)))modified_src/ +SOURCE_DIRS += $(MEANFIELD_DIR) + +# Define a rule to find the source directory of the given file. +# This attempts to find each of SOURCE_DIRS within the given file name; the +# first one that matches is then returned. If none match, an empty string +# will be returned. +define get_source_dir#(file) +$(firstword $(strip $(foreach d, $(sort $(SOURCE_DIRS)), $(findstring $(d), $(1))))) +endef + +# Define rule to strip any SOURCE_DIRS from source_file to allow use via local.mk. +# If no match is found, the value is returned untouched +# (though this will probably fail later). +define strip_source_dirs#(source_file) +$(or $(patsubst $(call get_source_dir, $(1))/%,%,$(1)), $(1)) +endef + +# Define a rule to replace any SOURCE_DIRS from header_file with the modified_src folder. +define replace_source_dirs#(header_file) +$(patsubst $(call get_source_dir, $(1))%, $(dir $(call get_source_dir, $(1)))modified_src%, $(1)) +endef + +# Need to build each neuron seperately or complier gets confused +# BUILD_DIR and APP_OUTPUT_DIR end with a / for historictical/ shared reasons +ifndef BUILD_DIR + BUILD_DIR := $(NEURAL_MODELLING_DIRS)/builds/$(APP)/ +endif +ifndef APP_OUTPUT_DIR + APP_OUTPUT_DIR := $(NEURAL_MODELLING_DIRS)/../spynnaker/pyNN/model_binaries +endif + +# Check if the neuron implementation is the default one +ifndef MEANFIELD_IMPL_H + $(error MEANFIELD_IMPL_H is not set. Please select a neuron implementation) +else + MEANFIELD_IMPL := $(call strip_source_dirs,$(MEANFIELD_IMPL_H)) + MEANFIELD_IMPL_H := $(call replace_source_dirs,$(MEANFIELD_IMPL_H)) + MEANFIELD_IMPL_STANDARD := meanfield/implementations/meanfield_impl_standard.h + MEANFIELD_INCLUDES := -include $(MEANFIELD_IMPL_H) + ifeq ($(MEANFIELD_IMPL), $(MEANFIELD_IMPL_STANDARD)) + + # Check required inputs and point them to modified sources + ifndef ADDITIONAL_INPUT_H + ADDITIONAL_INPUT_H = $(MODIFIED_DIR)meanfield/additional_inputs/additional_input_none_impl.h + else + ADDITIONAL_INPUT_H := $(call replace_source_dirs,$(ADDITIONAL_INPUT_H)) + endif + + ifndef MEANFIELD_MODEL + $(error MEANFIELD_MODEL is not set. Please choose a neuron model to compile) + else + MEANFIELD_MODEL := $(call strip_source_dirs,$(MEANFIELD_MODEL)) + endif + + ifndef MEANFIELD_MODEL_H + $(error MEANFIELD_MODEL is not set. Please choose a neuron model to compile) + else + MEANFIELD_MODEL_H := $(call replace_source_dirs,$(MEANFIELD_MODEL_H)) + endif + + + ifndef CONFIG_H + $(error CONFIG_H is not set. Please select an input type header file) + else + CONFIG_H := $(call replace_source_dirs,$(CONFIG_H)) + endif + + ifndef INPUT_TYPE_H + $(error INPUT_TYPE_H is not set. Please select an input type header file) + else + INPUT_TYPE_H := $(call replace_source_dirs,$(INPUT_TYPE_H)) + endif + +# ifndef MATHSBOX_H +# $(error MATHSBOX_H is not set. Please select an input type header file) +# else +# MATHSBOX_H := $(call replace_source_dirs,$(MATHSBOX_H)) +# endif + + ifndef THRESHOLD_TYPE_H + $(error THRESHOLD_TYPE_H is not set. Please select a threshold type header file) + else + THRESHOLD_TYPE_H := $(call replace_source_dirs,$(THRESHOLD_TYPE_H)) + endif + + ifndef SYNAPSE_TYPE_H + $(error SYNAPSE_TYPE_H is not set. Please select a synapse type header file) + else + SYNAPSE_TYPE_H := $(call replace_source_dirs,$(SYNAPSE_TYPE_H)) + endif + + MEANFIELD_INCLUDES := \ + -include $(MEANFIELD_MODEL_H) \ + -include $(SYNAPSE_TYPE_H) \ + -include $(CONFIG_H)\ + -include $(MATHSBOX_H) \ + -include $(INPUT_TYPE_H) \ + -include $(THRESHOLD_TYPE_H) \ + -include $(ADDITIONAL_INPUT_H) \ + -include $(MEANFIELD_IMPL_H) + endif +endif + +ifndef SYNAPSE_DYNAMICS + $(error SYNAPSE_DYNAMICS is not set. Please select a synapse dynamics implementation) +else + SYNAPSE_DYNAMICS_C := $(call replace_source_dirs,$(SYNAPSE_DYNAMICS)) + SYNAPSE_DYNAMICS := $(call strip_source_dirs,$(SYNAPSE_DYNAMICS)) + SYNAPSE_DYNAMICS_O := $(BUILD_DIR)$(SYNAPSE_DYNAMICS:%.c=%.o) + + SYNAPSE_DYNAMICS_STATIC := meanfield/plasticity/synapse_dynamics_static_impl.c + STDP_ENABLED = 0 + ifneq ($(SYNAPSE_DYNAMICS), $(SYNAPSE_DYNAMICS_STATIC)) + STDP_ENABLED = 1 + + ifndef TIMING_DEPENDENCE_H + $(error TIMING_DEPENDENCE_H is not set which is required when SYNAPSE_DYNAMICS ($(SYNAPSE_DYNAMICS_C)) != $(SYNAPSE_DYNAMICS_STATIC)) + endif + ifndef WEIGHT_DEPENDENCE_H + $(error WEIGHT_DEPENDENCE_H is not set which is required when SYNAPSE_DYNAMICS ($(SYNAPSE_DYNAMICS_C)) != $(SYNAPSE_DYNAMICS_STATIC)) + endif + endif +endif + +ifdef WEIGHT_DEPENDENCE + WEIGHT_DEPENDENCE_H := $(call replace_source_dirs,$(WEIGHT_DEPENDENCE_H)) + WEIGHT_DEPENDENCE_C := $(call replace_source_dirs,$(WEIGHT_DEPENDENCE)) + WEIGHT_DEPENDENCE := $(call strip_source_dirs,$(WEIGHT_DEPENDENCE)) + WEIGHT_DEPENDENCE_O := $(BUILD_DIR)$(WEIGHT_DEPENDENCE:%.c=%.o) +endif + +ifdef TIMING_DEPENDENCE + TIMING_DEPENDENCE_H := $(call replace_source_dirs,$(TIMING_DEPENDENCE_H)) + TIMING_DEPENDENCE_C := $(call replace_source_dirs,$(TIMING_DEPENDENCE)) + TIMING_DEPENDENCE := $(call strip_source_dirs,$(TIMING_DEPENDENCE)) + TIMING_DEPENDENCE_O := $(BUILD_DIR)$(TIMING_DEPENDENCE:%.c=%.o) +endif + +SYNGEN_ENABLED = 1 +ifndef SYNAPTOGENESIS_DYNAMICS + SYNAPTOGENESIS_DYNAMICS := meanfield/structural_plasticity/synaptogenesis_dynamics_static_impl.c + SYNAPTOGENESIS_DYNAMICS_C := $(MODIFIED_DIR)$(SYNAPTOGENESIS_DYNAMICS) + SYNGEN_ENABLED = 0 +else + SYNAPTOGENESIS_DYNAMICS_C := $(call replace_source_dirs,$(SYNAPTOGENESIS_DYNAMICS)) + SYNAPTOGENESIS_DYNAMICS := $(call strip_source_dirs,$(SYNAPTOGENESIS_DYNAMICS)) + ifndef PARTNER_SELECTION + $(error PARTNER_SELECTION is not set which is required when SYNAPTOGENESIS_DYNAMICS is set) + endif + ifndef FORMATION + $(error FORMATION is not set which is required when SYNAPTOGENESIS_DYNAMICS is set) + endif + ifndef ELIMINATION + $(error ELIMINATION is not set which is required when SYNAPTOGENESIS_DYNAMICS is set) + endif +endif +SYNAPTOGENESIS_DYNAMICS_O := $(BUILD_DIR)$(SYNAPTOGENESIS_DYNAMICS:%.c=%.o) + +ifdef PARTNER_SELECTION + PARTNER_SELECTION_H := $(call replace_source_dirs,$(PARTNER_SELECTION_H)) + PARTNER_SELECTION_C := $(call replace_source_dirs,$(PARTNER_SELECTION)) + PARTNER_SELECTION := $(call strip_source_dirs,$(PARTNER_SELECTION)) + PARTNER_SELECTION_O := $(BUILD_DIR)$(PARTNER_SELECTION:%.c=%.o) +endif + +ifdef FORMATION + FORMATION_H := $(call replace_source_dirs,$(FORMATION_H)) + FORMATION_C := $(call replace_source_dirs,$(FORMATION)) + FORMATION := $(call strip_source_dirs,$(FORMATION)) + FORMATION_O := $(BUILD_DIR)$(FORMATION:%.c=%.o) +endif + +ifdef ELIMINATION + ELIMINATION_H := $(call replace_source_dirs,$(ELIMINATION_H)) + ELIMINATION_C := $(call replace_source_dirs,$(ELIMINATION)) + ELIMINATION := $(call strip_source_dirs,$(ELIMINATION)) + ELIMINATION_O := $(BUILD_DIR)$(ELIMINATION:%.c=%.o) +endif + +OTHER_SOURCES_CONVERTED := $(call strip_source_dirs,$(OTHER_SOURCES)) + +# List all the sources relative to one of SOURCE_DIRS +SOURCES = meanfield/c_main.c \ + meanfield/synapses.c \ + meanfield/direct_synapses.c \ + meanfield/meanfield.c \ + meanfield/meanfield_recording.c \ + meanfield/spike_processing.c \ + meanfield/population_table/population_table_$(POPULATION_TABLE_IMPL)_impl.c \ + $(MEANFIELD_MODEL) $(SYNAPSE_DYNAMICS) $(WEIGHT_DEPENDENCE) \ + $(TIMING_DEPENDENCE) $(SYNAPTOGENESIS_DYNAMICS) \ + $(PARTNER_SELECTION) $(FORMATION) $(ELIMINATION) $(OTHER_SOURCES_CONVERTED) + +include $(SPINN_DIRS)/make/local.mk + +FEC_OPT = $(OTIME) + +# Synapse build rules +SYNAPSE_TYPE_COMPILE = $(CC) -DLOG_LEVEL=$(SYNAPSE_DEBUG) $(CFLAGS) -DSTDP_ENABLED=$(STDP_ENABLED) +TEST_COMPILE = $(CC) -DLOG_LEVEL=$(SYNAPSE_DEBUG) $(CFLAGS) -DSTDP_ENABLED=1 + +$(BUILD_DIR)meanfield/c_main.o: $(MODIFIED_DIR)meanfield/c_main.c + #c_main.c + -@mkdir -p $(dir $@) + $(SYNAPSE_TYPE_COMPILE) -o $@ $< + +$(BUILD_DIR)meanfield/synapses.o: $(MODIFIED_DIR)meanfield/synapses.c + #synapses.c + -@mkdir -p $(dir $@) + $(SYNAPSE_TYPE_COMPILE) -o $@ $< + +$(BUILD_DIR)meanfield/meanfield.o: $(MODIFIED_DIR)meanfield/meanfield.c + #synapses.c + -@mkdir -p $(dir $@) + $(TEST_COMPILE) -o $@ $< + +$(BUILD_DIR)meanfield/direct_synapses.o: $(MODIFIED_DIR)meanfield/direct_synapses.c + #direct_synapses.c + -mkdir -p $(dir $@) + $(SYNAPSE_TYPE_COMPILE) -o $@ $< + +$(BUILD_DIR)meanfield/spike_processing.o: $(MODIFIED_DIR)meanfield/spike_processing.c + #spike_processing.c + -@mkdir -p $(dir $@) + $(SYNAPSE_TYPE_COMPILE) -o $@ $< + +$(BUILD_DIR)meanfield/population_table/population_table_binary_search_impl.o: $(MODIFIED_DIR)meanfield/population_table/population_table_binary_search_impl.c + #population_table/population_table_binary_search_impl.c + -@mkdir -p $(dir $@) + $(SYNAPSE_TYPE_COMPILE) -o $@ $< + +SYNGEN_INCLUDES:= +ifeq ($(SYNGEN_ENABLED), 1) + SYNGEN_INCLUDES:= -include $(PARTNER_SELECTION_H) -include $(FORMATION_H) -include $(ELIMINATION_H) +endif + +#STDP Build rules If and only if STDP used +ifeq ($(STDP_ENABLED), 1) + STDP_INCLUDES:= -include $(SYNAPSE_TYPE_H) -include $(WEIGHT_DEPENDENCE_H) -include $(TIMING_DEPENDENCE_H) + STDP_COMPILE = $(CC) -DLOG_LEVEL=$(PLASTIC_DEBUG) $(CFLAGS) -DSTDP_ENABLED=$(STDP_ENABLED) -DSYNGEN_ENABLED=$(SYNGEN_ENABLED) $(STDP_INCLUDES) + + $(SYNAPSE_DYNAMICS_O): $(SYNAPSE_DYNAMICS_C) + # SYNAPSE_DYNAMICS_O stdp + -@mkdir -p $(dir $@) + $(STDP_COMPILE) -o $@ $< + + $(SYNAPTOGENESIS_DYNAMICS_O): $(SYNAPTOGENESIS_DYNAMICS_C) + # SYNAPTOGENESIS_DYNAMICS_O stdp + -@mkdir -p $(dir $@) + $(STDP_COMPILE) $(SYNGEN_INCLUDES) -o $@ $< + + $(BUILD_DIR)meanfield/plasticity/common/post_events.o: $(MODIFIED_DIR)meanfield/plasticity/common/post_events.c + # plasticity/common/post_events.c + -@mkdir -p $(dir $@) + $(STDP_COMPILE) -o $@ $< + +else + $(SYNAPTOGENESIS_DYNAMICS_O): $(SYNAPTOGENESIS_DYNAMICS_C) + # $(SYNAPTOGENESIS_DYNAMICS) Synapese + -@mkdir -p $(dir $@) + $(SYNAPSE_TYPE_COMPILE) $(SYNGEN_INCLUDES) -o $@ $< + + $(SYNAPSE_DYNAMICS_O): $(SYNAPSE_DYNAMICS_C) + # SYNAPSE_DYNAMICS_O Synapese + -@mkdir -p $(dir $@) + $(SYNAPSE_TYPE_COMPILE) -o $@ $< + +endif + +$(WEIGHT_DEPENDENCE_O): $(WEIGHT_DEPENDENCE_C) $(SYNAPSE_TYPE_H) + # WEIGHT_DEPENDENCE_O + -@mkdir -p $(dir $@) + $(CC) -DLOG_LEVEL=$(PLASTIC_DEBUG) $(CFLAGS) \ + -o $@ $< + +$(TIMING_DEPENDENCE_O): $(TIMING_DEPENDENCE_C) $(SYNAPSE_TYPE_H) \ + $(WEIGHT_DEPENDENCE_H) + # TIMING_DEPENDENCE_O + -@mkdir -p $(dir $@) + $(CC) -DLOG_LEVEL=$(PLASTIC_DEBUG) $(CFLAGS) \ + -include $(WEIGHT_DEPENDENCE_H) -o $@ $< + +$(PARTNER_SELECTION_O): $(PARTNER_SELECTION_C) $(SYNAPSE_TYPE_H) + # PARTNER_SELECTION_O + -mkdir -p $(dir $@) + $(CC) -DLOG_LEVEL=$(PLASTIC_DEBUG) $(CFLAGS) \ + -include $(SYNAPSE_TYPE_H) -o $@ $< + +$(FORMATION_O): $(FORMATION_C) $(SYNAPSE_TYPE_H) + # FORMATION_O + -mkdir -p $(dir $@) + $(CC) -DLOG_LEVEL=$(PLASTIC_DEBUG) $(CFLAGS) \ + -include $(SYNAPSE_TYPE_H) -o $@ $< + +$(ELIMINATION_O): $(ELIMINATION_C) $(SYNAPSE_TYPE_H) + # ELIMINATION_O + -mkdir -p $(dir $@) + $(CC) -DLOG_LEVEL=$(PLASTIC_DEBUG) $(CFLAGS) \ + -include $(SYNAPSE_TYPE_H) -o $@ $< + +$(BUILD_DIR)meanfield/meanfield.o: $(MODIFIED_DIR)meanfield/meanfield.c + # meanfield.o + -@mkdir -p $(dir $@) + $(CC) -DLOG_LEVEL=$(NEURON_DEBUG) $(CFLAGS) $(MEANFIELD_INCLUDES) -o $@ $< + +$(BUILD_DIR)meanfield/meanfield_recording.o: $(MODIFIED_DIR)meanfield/meanfield_recording.c + # meanfield_recording.o + -@mkdir -p $(dir $@) + $(CC) -DLOG_LEVEL=$(NEURON_DEBUG) $(CFLAGS) $(MEANFIELD_INCLUDES) -o $@ $< + +.PRECIOUS: $(MODIFIED_DIR)%.c $(MODIFIED_DIR)%.h $(LOG_DICT_FILE) $(EXTRA_PRECIOUS) diff --git a/neural_modelling/makefiles/meanfield/meanfield_model_cond/Makefile b/neural_modelling/makefiles/meanfield/meanfield_model_cond/Makefile new file mode 100644 index 00000000000..debcd591ab6 --- /dev/null +++ b/neural_modelling/makefiles/meanfield/meanfield_model_cond/Makefile @@ -0,0 +1,13 @@ +APP = $(notdir $(CURDIR)) + +MEANFIELD_MODEL = $(MEANFIELD_DIR)/meanfield/models/meanfield_model_impl.c +MEANFIELD_MODEL_H = $(MEANFIELD_DIR)/meanfield/models/meanfield_model_impl.h +CONFIG_H = $(MEANFIELD_DIR)/meanfield/models/config.h +INPUT_TYPE_H = $(MEANFIELD_DIR)/meanfield/input_types/input_type_none.h +MATHSBOX_H = $(MEANFIELD_DIR)/meanfield/models/mathsbox.h +MEANFIELD_IMPL_H = $(MEANFIELD_DIR)/meanfield/implementations/meanfield_impl_standard.h +THRESHOLD_TYPE_H = $(MEANFIELD_DIR)/meanfield/threshold_types/threshold_type_none.h +SYNAPSE_TYPE_H = $(MEANFIELD_DIR)/meanfield/synapse_types/synapse_types_exponential_impl.h +SYNAPSE_DYNAMICS = $(MEANFIELD_DIR)/meanfield/plasticity/synapse_dynamics_static_impl.c + +include ../meanfield_build.mk diff --git a/neural_modelling/makefiles/meanfield/spynnaker.cfg b/neural_modelling/makefiles/meanfield/spynnaker.cfg new file mode 100644 index 00000000000..3e9927182c5 --- /dev/null +++ b/neural_modelling/makefiles/meanfield/spynnaker.cfg @@ -0,0 +1,8 @@ +[Reports] +default_report_file_path = DEFAULT +max_report_kept = 5 +extract_iobuf=True + + +[Mode] +mode=production diff --git a/neural_modelling/makefiles/meanfield/untitled.txt b/neural_modelling/makefiles/meanfield/untitled.txt new file mode 100644 index 00000000000..7f743485a7a --- /dev/null +++ b/neural_modelling/makefiles/meanfield/untitled.txt @@ -0,0 +1,11 @@ +#MEANFIELD_MODEL_H = $(MEANFIELD_DIR)/meanfield/models/meanfield_model.h +#CONFIG_H = $(MEANFIELD_DIR)/meanfield/models/config.h +#MATHSBOX_H = $(MEANFIELD_DIR)/meanfield/models/mathsbox.h +#MEANFIELD_H = $(MEANFIELD_DIR)/meanfield/meanfield.h +#MEANFIELD = $(MEANFIELD_DIR)/meanfield/meanfield.c +#MEANFIELD_RECORDING_H = $(MEANFIELD_DIR)/meanfield/meanfield_recording.h +#MEANFIELD_RECORDING = $(MEANFIELD_DIR)/meanfield/meanfield_recording.c +#C_MAINS = $(MEANFIELD_DIR)/meanfield/c_main.c + +#TIMING_DEPENDENCE_H = $(MEANFIELD_DIR)/meanfield/plasticity/stdp/timing_dependence/timing_nearest_pair_impl.h +#WEIGHT_DEPENDENCE_H = $(MEANFIELD_DIR)/meanfield/plasticity/stdp/weight_dependence/weight_additive_one_term_impl.h \ No newline at end of file diff --git a/neural_modelling/makefiles/meanfield_fixing/.spynnaker.cfg b/neural_modelling/makefiles/meanfield_fixing/.spynnaker.cfg new file mode 100644 index 00000000000..a0a72a2c0ec --- /dev/null +++ b/neural_modelling/makefiles/meanfield_fixing/.spynnaker.cfg @@ -0,0 +1,3 @@ +[Reports] + +exctract_iobuf=True diff --git a/neural_modelling/makefiles/meanfield_fixing/Makefile b/neural_modelling/makefiles/meanfield_fixing/Makefile new file mode 100644 index 00000000000..1a04f4c705d --- /dev/null +++ b/neural_modelling/makefiles/meanfield_fixing/Makefile @@ -0,0 +1,22 @@ +# Copyright (c) 2017-2019 The University of Manchester +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +MODELS = meanfield_model_cond_fixing + +all: + for d in $(MODELS); do $(MAKE) -C $$d || exit $$?; done + +clean: + for d in $(MODELS); do $(MAKE) -C $$d clean || exit $$?; done diff --git a/neural_modelling/makefiles/meanfield_fixing/meanfield_build.mk b/neural_modelling/makefiles/meanfield_fixing/meanfield_build.mk new file mode 100644 index 00000000000..6874c6988c4 --- /dev/null +++ b/neural_modelling/makefiles/meanfield_fixing/meanfield_build.mk @@ -0,0 +1,379 @@ +# See Notes in sPyNNaker/neural_modelling/CHANGES_April_2018 + +# Copyright (c) 2017-2019 The University of Manchester +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# If SPINN_DIRS is not defined, this is an error! +ifndef SPINN_DIRS + $(error SPINN_DIRS is not set. Please define SPINN_DIRS (possibly by running "source setup" in the spinnaker package folder)) +endif + +# If NEURAL_MODELLING_DIRS is not defined, this is an error! +ifndef NEURAL_MODELLING_DIRS + $(error NEURAL_MODELLING_DIRS is not set. Please define NEURAL_MODELLING_DIRS (possibly by running "source setup" in the sPyNNaker folder)) +endif +#Check NEURAL_MODELLING_DIRS +MAKEFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +CHECK_PATH := $(NEURAL_MODELLING_DIRS)/makefiles/meanfield_fixing/meanfield_build.mk +ifneq ($(CHECK_PATH), $(MAKEFILE_PATH)) + $(error Please check NEURAL_MODELLING_DIRS as based on that this file is at $(CHECK_PATH) when it is actually at $(MAKEFILE_PATH)) +endif + +# Set logging levels +ifeq ($(SPYNNAKER_DEBUG), DEBUG) + NEURON_DEBUG = LOG_DEBUG + SYNAPSE_DEBUG = LOG_DEBUG + PLASTIC_DEBUG = LOG_DEBUG +endif + +ifndef NEURON_DEBUG + NEURON_DEBUG = LOG_INFO +endif + +ifndef SYNAPSE_DEBUG + SYNAPSE_DEBUG = LOG_INFO +endif + +ifndef PLASTIC_DEBUG + PLASTIC_DEBUG = LOG_INFO +endif + +#POPULATION_TABLE_IMPL := fixed +POPULATION_TABLE_IMPL := binary_search + +# Add source directory + +# Define the directories +# Path flag to replace with the modified dir (abspath drops the final /) +MEANFIELD_DIR := $(abspath $(NEURAL_MODELLING_DIRS)/src) +MODIFIED_DIR :=$(dir $(abspath $(MEANFIELD_DIR)))modified_src/ +SOURCE_DIRS += $(MEANFIELD_DIR) + +# Define a rule to find the source directory of the given file. +# This attempts to find each of SOURCE_DIRS within the given file name; the +# first one that matches is then returned. If none match, an empty string +# will be returned. +define get_source_dir#(file) +$(firstword $(strip $(foreach d, $(sort $(SOURCE_DIRS)), $(findstring $(d), $(1))))) +endef + +# Define rule to strip any SOURCE_DIRS from source_file to allow use via local.mk. +# If no match is found, the value is returned untouched +# (though this will probably fail later). +define strip_source_dirs#(source_file) +$(or $(patsubst $(call get_source_dir, $(1))/%,%,$(1)), $(1)) +endef + +# Define a rule to replace any SOURCE_DIRS from header_file with the modified_src folder. +define replace_source_dirs#(header_file) +$(patsubst $(call get_source_dir, $(1))%, $(dir $(call get_source_dir, $(1)))modified_src%, $(1)) +endef + +# Need to build each neuron seperately or complier gets confused +# BUILD_DIR and APP_OUTPUT_DIR end with a / for historictical/ shared reasons +ifndef BUILD_DIR + BUILD_DIR := $(NEURAL_MODELLING_DIRS)/builds/$(APP)/ +endif +ifndef APP_OUTPUT_DIR + APP_OUTPUT_DIR := $(NEURAL_MODELLING_DIRS)/../spynnaker/pyNN/model_binaries +endif + +# Check if the neuron implementation is the default one +ifndef MEANFIELD_IMPL_STD_H + $(error MEANFIELD_IMPL_STD_H is not set. Please select a neuron implementation) +else + MEANFIELD_IMPL := $(call strip_source_dirs,$(MEANFIELD_IMPL_STD_H)) + MEANFIELD_IMPL_STD_H := $(call replace_source_dirs,$(MEANFIELD_IMPL_STD_H)) + MEANFIELD_IMPL_STANDARD := meanfield_fixing/implementations/meanfield_impl_standard.h + MEANFIELD_INCLUDES := -include $(MEANFIELD_IMPL_STD_H) + ifeq ($(MEANFIELD_IMPL), $(MEANFIELD_IMPL_STANDARD)) + + # Check required inputs and point them to modified sources + ifndef ADDITIONAL_INPUT_H + ADDITIONAL_INPUT_H = $(MODIFIED_DIR)meanfield_fixing/additional_inputs/additional_input_none_impl.h + else + ADDITIONAL_INPUT_H := $(call replace_source_dirs,$(ADDITIONAL_INPUT_H)) + endif + + ifndef MEANFIELD_MODEL_H + $(error MEANFIELD_MODEL_H is not set. Please choose a neuron model to compile) + else + MEANFIELD_MODEL_H := $(call strip_source_dirs,$(MEANFIELD_MODEL_H)) + endif + + ifndef MEANFIELD_MODEL_IMPL + $(error MEANFIELD_MODEL_IMPL is not set. Please choose a neuron model to compile) + else + MEANFIELD_MODEL_IMPL := $(call strip_source_dirs,$(MEANFIELD_MODEL_IMPL)) + endif + + ifndef MEANFIELD_MODEL_IMPL_H + $(error MEANFIELD_MODEL_IMPL_H is not set. Please choose a neuron model to compile) + else + MEANFIELD_MODEL_IMPL_H := $(call replace_source_dirs,$(MEANFIELD_MODEL_IMPL_H)) + endif + + ifndef CONFIG_H + $(error CONFIG_H is not set. Please select an input type header file) + else + CONFIG_H := $(call replace_source_dirs,$(CONFIG_H)) + endif + + ifndef SYNAPSE_TYPE_H + $(error SYNAPSE_TYPE_H is not set. Please select a synapse type header file) + else + SYNAPSE_TYPE_H := $(call replace_source_dirs,$(SYNAPSE_TYPE_H)) + endif + + ifndef INPUT_TYPE_H + $(error INPUT_TYPE_H is not set. Please select an input type header file) + else + INPUT_TYPE_H := $(call replace_source_dirs,$(INPUT_TYPE_H)) + endif + + ifndef MATHSBOX_H + $(error MATHSBOX_H is not set. Please select an input type header file) + else + MATHSBOX_H := $(call replace_source_dirs,$(MATHSBOX_H)) + endif + + ifndef THRESHOLD_TYPE_H + $(error THRESHOLD_TYPE_H is not set. Please select a threshold type header file) + else + THRESHOLD_TYPE_H := $(call replace_source_dirs,$(THRESHOLD_TYPE_H)) + endif + + + MEANFIELD_INCLUDES := \ + -include $(MEANFIELD_MODEL_H) \ + -include $(MEANFIELD_MODEL_IMPL_H) \ + -include $(CONFIG_H) \ + -include $(MATHSBOX_H) \ + -include $(SYNAPSE_TYPE_H) \ + -include $(INPUT_TYPE_H) \ + -include $(THRESHOLD_TYPE_H) \ + -include $(ADDITIONAL_INPUT_H) \ + -include $(MEANFIELD_IMPL_STD_H) + endif +endif + +ifndef SYNAPSE_DYNAMICS + $(error SYNAPSE_DYNAMICS is not set. Please select a synapse dynamics implementation) +else + SYNAPSE_DYNAMICS_C := $(call replace_source_dirs,$(SYNAPSE_DYNAMICS)) + SYNAPSE_DYNAMICS := $(call strip_source_dirs,$(SYNAPSE_DYNAMICS)) + SYNAPSE_DYNAMICS_O := $(BUILD_DIR)$(SYNAPSE_DYNAMICS:%.c=%.o) + + SYNAPSE_DYNAMICS_STATIC := meanfield_fixing/plasticity/synapse_dynamics_static_impl.c + STDP_ENABLED = 0 + ifneq ($(SYNAPSE_DYNAMICS), $(SYNAPSE_DYNAMICS_STATIC)) + STDP_ENABLED = 1 + + ifndef TIMING_DEPENDENCE_H + $(error TIMING_DEPENDENCE_H is not set which is required when SYNAPSE_DYNAMICS ($(SYNAPSE_DYNAMICS_C)) != $(SYNAPSE_DYNAMICS_STATIC)) + endif + ifndef WEIGHT_DEPENDENCE_H + $(error WEIGHT_DEPENDENCE_H is not set which is required when SYNAPSE_DYNAMICS ($(SYNAPSE_DYNAMICS_C)) != $(SYNAPSE_DYNAMICS_STATIC)) + endif + endif +endif + +ifdef WEIGHT_DEPENDENCE + WEIGHT_DEPENDENCE_H := $(call replace_source_dirs,$(WEIGHT_DEPENDENCE_H)) + WEIGHT_DEPENDENCE_C := $(call replace_source_dirs,$(WEIGHT_DEPENDENCE)) + WEIGHT_DEPENDENCE := $(call strip_source_dirs,$(WEIGHT_DEPENDENCE)) + WEIGHT_DEPENDENCE_O := $(BUILD_DIR)$(WEIGHT_DEPENDENCE:%.c=%.o) +endif + +ifdef TIMING_DEPENDENCE + TIMING_DEPENDENCE_H := $(call replace_source_dirs,$(TIMING_DEPENDENCE_H)) + TIMING_DEPENDENCE_C := $(call replace_source_dirs,$(TIMING_DEPENDENCE)) + TIMING_DEPENDENCE := $(call strip_source_dirs,$(TIMING_DEPENDENCE)) + TIMING_DEPENDENCE_O := $(BUILD_DIR)$(TIMING_DEPENDENCE:%.c=%.o) +endif + +SYNGEN_ENABLED = 1 +ifndef SYNAPTOGENESIS_DYNAMICS + SYNAPTOGENESIS_DYNAMICS := meanfield_fixing/structural_plasticity/synaptogenesis_dynamics_static_impl.c + SYNAPTOGENESIS_DYNAMICS_C := $(MODIFIED_DIR)$(SYNAPTOGENESIS_DYNAMICS) + SYNGEN_ENABLED = 0 +else + SYNAPTOGENESIS_DYNAMICS_C := $(call replace_source_dirs,$(SYNAPTOGENESIS_DYNAMICS)) + SYNAPTOGENESIS_DYNAMICS := $(call strip_source_dirs,$(SYNAPTOGENESIS_DYNAMICS)) + ifndef PARTNER_SELECTION + $(error PARTNER_SELECTION is not set which is required when SYNAPTOGENESIS_DYNAMICS is set) + endif + ifndef FORMATION + $(error FORMATION is not set which is required when SYNAPTOGENESIS_DYNAMICS is set) + endif + ifndef ELIMINATION + $(error ELIMINATION is not set which is required when SYNAPTOGENESIS_DYNAMICS is set) + endif +endif +SYNAPTOGENESIS_DYNAMICS_O := $(BUILD_DIR)$(SYNAPTOGENESIS_DYNAMICS:%.c=%.o) + +ifdef PARTNER_SELECTION + PARTNER_SELECTION_H := $(call replace_source_dirs,$(PARTNER_SELECTION_H)) + PARTNER_SELECTION_C := $(call replace_source_dirs,$(PARTNER_SELECTION)) + PARTNER_SELECTION := $(call strip_source_dirs,$(PARTNER_SELECTION)) + PARTNER_SELECTION_O := $(BUILD_DIR)$(PARTNER_SELECTION:%.c=%.o) +endif + +ifdef FORMATION + FORMATION_H := $(call replace_source_dirs,$(FORMATION_H)) + FORMATION_C := $(call replace_source_dirs,$(FORMATION)) + FORMATION := $(call strip_source_dirs,$(FORMATION)) + FORMATION_O := $(BUILD_DIR)$(FORMATION:%.c=%.o) +endif + +ifdef ELIMINATION + ELIMINATION_H := $(call replace_source_dirs,$(ELIMINATION_H)) + ELIMINATION_C := $(call replace_source_dirs,$(ELIMINATION)) + ELIMINATION := $(call strip_source_dirs,$(ELIMINATION)) + ELIMINATION_O := $(BUILD_DIR)$(ELIMINATION:%.c=%.o) +endif + +OTHER_SOURCES_CONVERTED := $(call strip_source_dirs,$(OTHER_SOURCES)) + +# List all the sources relative to one of SOURCE_DIRS +SOURCES = meanfield_fixing/c_main.c \ + meanfield_fixing/synapses.c \ + meanfield_fixing/direct_synapses.c \ + meanfield_fixing/meanfield.c \ + meanfield_fixing/meanfield_recording.c \ + meanfield_fixing/models/meanfield_model_impl.c \ + meanfield_fixing/spike_processing.c \ + meanfield_fixing/population_table/population_table_$(POPULATION_TABLE_IMPL)_impl.c \ + $(SYNAPSE_DYNAMICS) $(WEIGHT_DEPENDENCE) \ + $(TIMING_DEPENDENCE) $(SYNAPTOGENESIS_DYNAMICS) \ + $(PARTNER_SELECTION) $(FORMATION) $(ELIMINATION) $(OTHER_SOURCES_CONVERTED) + +include $(SPINN_DIRS)/make/local.mk + +FEC_OPT = $(OTIME) + +# Synapse build rules +SYNAPSE_TYPE_COMPILE = $(CC) -DLOG_LEVEL=$(SYNAPSE_DEBUG) $(CFLAGS) -DSTDP_ENABLED=$(STDP_ENABLED) +TEST_COMPILE = $(CC) -DLOG_LEVEL=$(SYNAPSE_DEBUG) $(CFLAGS) -DSTDP_ENABLED=1 + +$(BUILD_DIR)meanfield_fixing/c_main.o: $(MODIFIED_DIR)meanfield_fixing/c_main.c + #c_main.c + -@mkdir -p $(dir $@) + $(SYNAPSE_TYPE_COMPILE) -o $@ $< + +$(BUILD_DIR)meanfield_fixing/synapses.o: $(MODIFIED_DIR)meanfield_fixing/synapses.c + #synapses.c + -@mkdir -p $(dir $@) + $(SYNAPSE_TYPE_COMPILE) -o $@ $< + +$(BUILD_DIR)meanfield_fixing/direct_synapses.o: $(MODIFIED_DIR)meanfield_fixing/direct_synapses.c + #direct_synapses.c + -mkdir -p $(dir $@) + $(SYNAPSE_TYPE_COMPILE) -o $@ $< + +$(BUILD_DIR)meanfield_fixing/spike_processing.o: $(MODIFIED_DIR)meanfield_fixing/spike_processing.c + #spike_processing.c + -@mkdir -p $(dir $@) + $(SYNAPSE_TYPE_COMPILE) -o $@ $< + +$(BUILD_DIR)meanfield_fixing/population_table/population_table_binary_search_impl.o: $(MODIFIED_DIR)meanfield_fixing/population_table/population_table_binary_search_impl.c + #population_table/population_table_binary_search_impl.c + -@mkdir -p $(dir $@) + $(SYNAPSE_TYPE_COMPILE) -o $@ $< + +SYNGEN_INCLUDES:= +ifeq ($(SYNGEN_ENABLED), 1) +endif + +#STDP Build rules If and only if STDP used +ifeq ($(STDP_ENABLED), 1) + STDP_INCLUDES:= -include $(SYNAPSE_TYPE_H) -include $(WEIGHT_DEPENDENCE_H) -include $(TIMING_DEPENDENCE_H) + STDP_COMPILE = $(CC) -DLOG_LEVEL=$(PLASTIC_DEBUG) $(CFLAGS) -DSTDP_ENABLED=$(STDP_ENABLED) -DSYNGEN_ENABLED=$(SYNGEN_ENABLED) $(STDP_INCLUDES) + + $(SYNAPSE_DYNAMICS_O): $(SYNAPSE_DYNAMICS_C) + # SYNAPSE_DYNAMICS_O stdp + -@mkdir -p $(dir $@) + $(STDP_COMPILE) -o $@ $< + + $(SYNAPTOGENESIS_DYNAMICS_O): $(SYNAPTOGENESIS_DYNAMICS_C) + # SYNAPTOGENESIS_DYNAMICS_O stdp + -@mkdir -p $(dir $@) + $(STDP_COMPILE) $(SYNGEN_INCLUDES) -o $@ $< + + $(BUILD_DIR)meanfield_fixing/plasticity/common/post_events.o: $(MODIFIED_DIR)meanfield_fixing/plasticity/common/post_events.c + # plasticity/common/post_events.c + -@mkdir -p $(dir $@) + $(STDP_COMPILE) -o $@ $< + +else + $(SYNAPTOGENESIS_DYNAMICS_O): $(SYNAPTOGENESIS_DYNAMICS_C) + # $(SYNAPTOGENESIS_DYNAMICS) Synapese + -@mkdir -p $(dir $@) + $(SYNAPSE_TYPE_COMPILE) $(SYNGEN_INCLUDES) -o $@ $< + + $(SYNAPSE_DYNAMICS_O): $(SYNAPSE_DYNAMICS_C) + # SYNAPSE_DYNAMICS_O Synapese + -@mkdir -p $(dir $@) + $(SYNAPSE_TYPE_COMPILE) -o $@ $< + +endif + +$(WEIGHT_DEPENDENCE_O): $(WEIGHT_DEPENDENCE_C) $(SYNAPSE_TYPE_H) + # WEIGHT_DEPENDENCE_O + -@mkdir -p $(dir $@) + $(CC) -DLOG_LEVEL=$(PLASTIC_DEBUG) $(CFLAGS) \ + -o $@ $< + +$(TIMING_DEPENDENCE_O): $(TIMING_DEPENDENCE_C) $(SYNAPSE_TYPE_H) \ + $(WEIGHT_DEPENDENCE_H) + # TIMING_DEPENDENCE_O + -@mkdir -p $(dir $@) + $(CC) -DLOG_LEVEL=$(PLASTIC_DEBUG) $(CFLAGS) \ + -include $(WEIGHT_DEPENDENCE_H) -o $@ $< + +$(PARTNER_SELECTION_O): $(PARTNER_SELECTION_C) $(SYNAPSE_TYPE_H) + # PARTNER_SELECTION_O + -mkdir -p $(dir $@) + $(CC) -DLOG_LEVEL=$(PLASTIC_DEBUG) $(CFLAGS) \ + -include $(SYNAPSE_TYPE_H) -o $@ $< + +$(FORMATION_O): $(FORMATION_C) $(SYNAPSE_TYPE_H) + # FORMATION_O + -mkdir -p $(dir $@) + $(CC) -DLOG_LEVEL=$(PLASTIC_DEBUG) $(CFLAGS) \ + -include $(SYNAPSE_TYPE_H) -o $@ $< + +$(ELIMINATION_O): $(ELIMINATION_C) $(SYNAPSE_TYPE_H) + # ELIMINATION_O + -mkdir -p $(dir $@) + $(CC) -DLOG_LEVEL=$(PLASTIC_DEBUG) $(CFLAGS) \ + -include $(SYNAPSE_TYPE_H) -o $@ $< + +$(BUILD_DIR)meanfield_fixing/meanfield.o: $(MODIFIED_DIR)meanfield_fixing/meanfield.c + # meanfield.o + -@mkdir -p $(dir $@) + $(CC) -DLOG_LEVEL=$(NEURON_DEBUG) $(CFLAGS) $(MEANFIELD_INCLUDES) -o $@ $< + +$(BUILD_DIR)meanfield_fixing/meanfield_recording.o: $(MODIFIED_DIR)meanfield_fixing/meanfield_recording.c + # meanfield_recording.o + -@mkdir -p $(dir $@) + $(CC) -DLOG_LEVEL=$(NEURON_DEBUG) $(CFLAGS) $(MEANFIELD_INCLUDES) -o $@ $< + +$(BUILD_DIR)meanfield_fixing/models/meanfield_model_impl.o: $(MODIFIED_DIR)meanfield_fixing/models/meanfield_model_impl.c + # models/meanfield_model_impl.o + -@mkdir -p $(dir $@) + $(CC) -DLOG_LEVEL=$(NEURON_DEBUG) $(CFLAGS) $(MEANFIELD_INCLUDES) -o $@ $< + +.PRECIOUS: $(MODIFIED_DIR)%.c $(MODIFIED_DIR)%.h $(LOG_DICT_FILE) $(EXTRA_PRECIOUS) diff --git a/neural_modelling/makefiles/meanfield_fixing/meanfield_model_cond_fixing/Makefile b/neural_modelling/makefiles/meanfield_fixing/meanfield_model_cond_fixing/Makefile new file mode 100644 index 00000000000..fc7e17b98d4 --- /dev/null +++ b/neural_modelling/makefiles/meanfield_fixing/meanfield_model_cond_fixing/Makefile @@ -0,0 +1,15 @@ +APP = $(notdir $(CURDIR)) + +MEANFIELD_MODEL_H = $(MEANFIELD_DIR)/meanfield_fixing/models/meanfield_model.h +MEANFIELD_MODEL_IMPL = $(MEANFIELD_DIR)/meanfield_fixing/models/meanfield_model_impl.c +MEANFIELD_MODEL_IMPL_H = $(MEANFIELD_DIR)/meanfield_fixing/models/meanfield_model_impl.h +CONFIG_H = $(MEANFIELD_DIR)/meanfield_fixing/models/config.h +SYNAPSE_TYPE_H = $(MEANFIELD_DIR)/meanfield_fixing/synapse_types/synapse_types_exponential_impl.h +INPUT_TYPE_H = $(MEANFIELD_DIR)/meanfield_fixing/input_types/input_type_none.h +MATHSBOX_H = $(MEANFIELD_DIR)/meanfield_fixing/models/mathsbox.h +MEANFIELD_IMPL_STD_H = $(MEANFIELD_DIR)/meanfield_fixing/implementations/meanfield_impl_standard.h +THRESHOLD_TYPE_H = $(MEANFIELD_DIR)/meanfield_fixing/threshold_types/threshold_type_none.h +SYNAPSE_TYPE_H = $(MEANFIELD_DIR)/meanfield_fixing/synapse_types/synapse_types_exponential_impl.h +SYNAPSE_DYNAMICS = $(MEANFIELD_DIR)/meanfield_fixing/plasticity/synapse_dynamics_static_impl.c + +include ../meanfield_build.mk diff --git a/neural_modelling/makefiles/meanfield_fixing/untitled.txt b/neural_modelling/makefiles/meanfield_fixing/untitled.txt new file mode 100644 index 00000000000..7f743485a7a --- /dev/null +++ b/neural_modelling/makefiles/meanfield_fixing/untitled.txt @@ -0,0 +1,11 @@ +#MEANFIELD_MODEL_H = $(MEANFIELD_DIR)/meanfield/models/meanfield_model.h +#CONFIG_H = $(MEANFIELD_DIR)/meanfield/models/config.h +#MATHSBOX_H = $(MEANFIELD_DIR)/meanfield/models/mathsbox.h +#MEANFIELD_H = $(MEANFIELD_DIR)/meanfield/meanfield.h +#MEANFIELD = $(MEANFIELD_DIR)/meanfield/meanfield.c +#MEANFIELD_RECORDING_H = $(MEANFIELD_DIR)/meanfield/meanfield_recording.h +#MEANFIELD_RECORDING = $(MEANFIELD_DIR)/meanfield/meanfield_recording.c +#C_MAINS = $(MEANFIELD_DIR)/meanfield/c_main.c + +#TIMING_DEPENDENCE_H = $(MEANFIELD_DIR)/meanfield/plasticity/stdp/timing_dependence/timing_nearest_pair_impl.h +#WEIGHT_DEPENDENCE_H = $(MEANFIELD_DIR)/meanfield/plasticity/stdp/weight_dependence/weight_additive_one_term_impl.h \ No newline at end of file diff --git a/neural_modelling/src/meanfield/additional_inputs/additional_input.h b/neural_modelling/src/meanfield/additional_inputs/additional_input.h new file mode 100644 index 00000000000..f3f376c86c7 --- /dev/null +++ b/neural_modelling/src/meanfield/additional_inputs/additional_input.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \dir +//! \brief Additional inputs to neuron models +//! \file +//! \brief API for additional inputs +#ifndef _ADDITIONAL_INPUT_TYPE_H_ +#define _ADDITIONAL_INPUT_TYPE_H_ + +#include + +// Forward declaration of the additional input pointer +struct additional_input_t; +typedef struct additional_input_t additional_input_t; +//! Pointer to additional_input_t +typedef additional_input_t *additional_input_pointer_t; + +//! \brief Gets the value of current provided by the additional input this +//! timestep +//! \param[in] additional_input: The additional input type pointer to the +//! parameters +//! \param[in] membrane_voltage: The membrane voltage of the neuron +//! \return The value of the input after scaling +static input_t additional_input_get_input_value_as_current( + struct additional_input_t *additional_input, + state_t membrane_voltage); + +//! \brief Notifies the additional input type that the neuron has spiked +//! \param[in] additional_input: The additional input type pointer to the +//! parameters +static void additional_input_has_spiked( + struct additional_input_t *additional_input); + +#endif // _ADDITIONAL_INPUT_TYPE_H_ diff --git a/neural_modelling/src/meanfield/additional_inputs/additional_input_none_impl.h b/neural_modelling/src/meanfield/additional_inputs/additional_input_none_impl.h new file mode 100644 index 00000000000..bb2d71236cc --- /dev/null +++ b/neural_modelling/src/meanfield/additional_inputs/additional_input_none_impl.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Implementation of "no-such-input" additional input +#ifndef _ADDITIONAL_INPUT_TYPE_NONE_H_ +#define _ADDITIONAL_INPUT_TYPE_NONE_H_ + +#include "additional_input.h" + +//! An empty additional input that makes no contribution +struct additional_input_t { +}; + +//! \brief Gets the value of current provided by the additional input this +//! timestep +//! \details Does nothing +//! \param[in] additional_input: The additional input type pointer to the +//! parameters +//! \param[in] membrane_voltage: The membrane voltage of the neuron +//! \return The value of the input after scaling +static inline input_t additional_input_get_input_value_as_current( + UNUSED struct additional_input_t *additional_input, + UNUSED state_t membrane_voltage) { + return 0; +} + +//! \brief Notifies the additional input type that the neuron has spiked +//! \details Does nothing +//! \param[in] additional_input: The additional input type pointer to the +//! parameters +static inline void additional_input_has_spiked( + UNUSED struct additional_input_t *additional_input) { +} + +#endif // _ADDITIONAL_INPUT_TYPE_NONE_H_ diff --git a/neural_modelling/src/meanfield/additional_inputs/my_additional_input.h b/neural_modelling/src/meanfield/additional_inputs/my_additional_input.h new file mode 100644 index 00000000000..48478430d9a --- /dev/null +++ b/neural_modelling/src/meanfield/additional_inputs/my_additional_input.h @@ -0,0 +1,35 @@ +#ifndef _ADDITIONAL_INPUT_H_ +#define _ADDITIONAL_INPUT_H_ + +#include + +typedef struct additional_input_t { + //REAL my_parameter; + //REAL input_current; +} additional_input_t; + + +//! \brief Gets the value of current provided by the additional input this +//! timestep +//! \param[in] additional_input The additional input type pointer to the +//! parameters +//! \param[in] membrane_voltage The membrane voltage of the neuron +//! \return The value of the input after scaling +static input_t additional_input_get_input_value_as_current( + additional_input_t *additional_input, + state_t membrane_voltage) { + use(membrane_voltage); + additional_input->input_current += additional_input->my_parameter; + return additional_input->input_current; +} + +//! \brief Notifies the additional input type that the neuron has spiked +//! \param[in] additional_input The additional input type pointer to the +//! parameters +static void additional_input_has_spiked( + additional_input_t *additional_input) { + additional_input->input_current = 0; +} + + +#endif // _MY_ADDITIONAL_INPUT_H_ diff --git a/neural_modelling/src/meanfield/c_main.c b/neural_modelling/src/meanfield/c_main.c new file mode 100644 index 00000000000..583e90c51c8 --- /dev/null +++ b/neural_modelling/src/meanfield/c_main.c @@ -0,0 +1,426 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/*! + * @dir + * @brief Implementation of simulator for a single neural population on a + * SpiNNaker CPU core. Or rather of a slice of a population. + * + * @file + * @brief This file contains the main function of the application framework, + * which the application programmer uses to configure and run applications. + * + * This is the main entrance class for most of the neural models. The following + * Figure shows how all of the c code + * interacts with each other and what classes + * are used to represent over arching logic + * (such as plasticity, spike processing, utilities, synapse types, models) + * + * @image html spynnaker_c_code_flow.png + */ + +#include +#include "regions.h" +#include "meanfield.h" +#include "synapses.h" +#include "spike_processing.h" +#include "population_table/population_table.h" +#include "plasticity/synapse_dynamics.h" +#include "structural_plasticity/synaptogenesis_dynamics.h" +#include "profile_tags.h" +#include "direct_synapses.h" + +#include +#include +#include +#include +#include +#include +#include + +/* validates that the model being compiled does indeed contain a application + * magic number*/ +#ifndef APPLICATION_NAME_HASH +#error APPLICATION_NAME_HASH was undefined. Make sure you define this\ + constant +#endif + +//! The provenance information written on application shutdown. +struct neuron_provenance { + //! A count of presynaptic events. + uint32_t n_pre_synaptic_events; + //! A count of synaptic saturations. + uint32_t n_synaptic_weight_saturations; + //! A count of the times that the synaptic input circular buffers overflowed + uint32_t n_input_buffer_overflows; + //! The current time. + uint32_t current_timer_tick; + //! The number of STDP weight saturations. + uint32_t n_plastic_synaptic_weight_saturations; + uint32_t n_ghost_pop_table_searches; + uint32_t n_failed_bitfield_reads; + uint32_t n_dmas_complete; + uint32_t n_spikes_processed; + uint32_t n_invalid_master_pop_table_hits; + uint32_t n_filtered_by_bitfield; + //! The number of rewirings performed. + uint32_t n_rewires; + uint32_t n_packets_dropped_from_lateness; + uint32_t spike_processing_get_max_filled_input_buffer_size; + //! the number of times the TDMA fully missed its slots + uint32_t n_tdma_mises; + //! Maximum backgrounds queued + uint32_t max_backgrounds_queued; + //! Background queue overloads + uint32_t n_background_queue_overloads; +}; + +//! values for the priority for each callback +typedef enum callback_priorities { + MC = -1, DMA = 0, USER = 0, TIMER = 0, SDP = 1, BACKGROUND = 1 +} callback_priorities; + +//! The number of regions that are to be used for recording +#define NUMBER_OF_REGIONS_TO_RECORD 4 + +// Globals + +//! The current timer tick value. +// the timer tick callback returning the same value. +uint32_t time; + +//! timer tick period (in microseconds) +static uint32_t timer_period; + +//! The number of timer ticks to run for before being expected to exit +static uint32_t simulation_ticks = 0; + +//! Determines if this model should run for infinite time +static uint32_t infinite_run; + +//! Timer callbacks since last rewiring +static int32_t last_rewiring_time = 0; + +//! Rewiring period represented as an integer +static int32_t rewiring_period = 0; + +//! Flag representing whether rewiring is enabled +static bool rewiring = false; + +//! Count the number of rewiring attempts +static uint32_t count_rewire_attempts = 0; + +//! The number of neurons on the core +static uint32_t n_neurons; + +//! The number of background tasks queued / running +static uint32_t n_backgrounds_queued = 0; + +//! The number of times the background couldn't be added +static uint32_t n_background_overloads = 0; + +//! The maximum number of background tasks queued +static uint32_t max_backgrounds_queued = 0; + +//! timer count for tdma of certain models; exported +uint global_timer_count; + + +//! \brief Callback to store provenance data (format: neuron_provenance). +//! \param[out] provenance_region: Where to write the provenance data +static void c_main_store_provenance_data(address_t provenance_region) { + log_debug("writing other provenance data"); + struct neuron_provenance *prov = (void *) provenance_region; + + // store the data into the provenance data region + prov->n_pre_synaptic_events = synapses_get_pre_synaptic_events(); + prov->n_synaptic_weight_saturations = synapses_saturation_count; + prov->n_input_buffer_overflows = spike_processing_get_buffer_overflows(); + prov->current_timer_tick = time; + prov->n_plastic_synaptic_weight_saturations = + synapse_dynamics_get_plastic_saturation_count(); + prov->n_ghost_pop_table_searches = ghost_pop_table_searches; + prov->n_failed_bitfield_reads = failed_bit_field_reads; + prov->n_dmas_complete = spike_processing_get_dma_complete_count(); + prov->n_spikes_processed = spike_processing_get_spike_processing_count(); + prov->n_invalid_master_pop_table_hits = invalid_master_pop_hits; + prov->n_filtered_by_bitfield = bit_field_filtered_packets; + prov->n_rewires = spike_processing_get_successful_rewires(); + prov->n_packets_dropped_from_lateness = + spike_processing_get_n_packets_dropped_from_lateness(); + prov->spike_processing_get_max_filled_input_buffer_size = + spike_processing_get_max_filled_input_buffer_size(); + prov->n_tdma_mises = tdma_processing_times_behind(); + prov->n_background_queue_overloads = n_background_overloads; + prov->max_backgrounds_queued = max_backgrounds_queued; + + log_debug("finished other provenance data"); +} + +//! \brief Initialises the model by reading in the regions and checking +//! recording data. +//! \return True if it successfully initialised, false otherwise +static bool initialise(void) { + log_debug("Initialise: started"); + + // Get the address this core's DTCM data starts at from SRAM + data_specification_metadata_t *ds_regions = + data_specification_get_data_address(); + + // Read the header + if (!data_specification_read_header(ds_regions)) { + return false; + } + + // Get the timing details and set up the simulation interface + if (!simulation_initialise( + data_specification_get_region(SYSTEM_REGION, ds_regions), + APPLICATION_NAME_HASH, &timer_period, &simulation_ticks, + &infinite_run, &time, SDP, DMA)) { + return false; + } + simulation_set_provenance_function( + c_main_store_provenance_data, + data_specification_get_region(PROVENANCE_DATA_REGION, ds_regions)); + + // Set up the neurons + uint32_t n_synapse_types; + uint32_t incoming_spike_buffer_size; + uint32_t n_regions_used; + if (!neuron_initialise( + data_specification_get_region(NEURON_PARAMS_REGION, ds_regions), + data_specification_get_region(NEURON_RECORDING_REGION, ds_regions), + &n_neurons, + &n_synapse_types, &incoming_spike_buffer_size, + &n_regions_used)) { + return false; + } + + // Set up the synapses + + uint32_t *ring_buffer_to_input_buffer_left_shifts; + bool clear_input_buffers_of_late_packets_init; + if (!synapses_initialise( + data_specification_get_region(SYNAPSE_PARAMS_REGION, ds_regions), + n_neurons, n_synapse_types, + &ring_buffer_to_input_buffer_left_shifts, + &clear_input_buffers_of_late_packets_init)) { + return false; + } + + + // set up direct synapses + + address_t direct_synapses_address; + if (!direct_synapses_initialise( + data_specification_get_region(DIRECT_MATRIX_REGION, ds_regions), + &direct_synapses_address)) { + return false; + } + + + // Set up the population table + uint32_t row_max_n_words; + if (!population_table_initialise( + data_specification_get_region(POPULATION_TABLE_REGION, ds_regions), + data_specification_get_region(SYNAPTIC_MATRIX_REGION, ds_regions), + direct_synapses_address, + &row_max_n_words)) { + return false; + } + // Set up the synapse dynamics + + if (!synapse_dynamics_initialise( + data_specification_get_region(SYNAPSE_DYNAMICS_REGION, ds_regions), + n_neurons, n_synapse_types, + ring_buffer_to_input_buffer_left_shifts)) { + return false; + } + + + // Set up structural plasticity dynamics + if (!synaptogenesis_dynamics_initialise(data_specification_get_region( + STRUCTURAL_DYNAMICS_REGION, ds_regions))) { + return false; + } + + rewiring_period = synaptogenesis_rewiring_period(); + rewiring = rewiring_period != -1; + + if (!spike_processing_initialise( + row_max_n_words, MC, USER, incoming_spike_buffer_size, + clear_input_buffers_of_late_packets_init, n_regions_used)) { + return false; + } + + + // Setup profiler + profiler_init(data_specification_get_region(PROFILER_REGION, ds_regions)); + + // Do bitfield configuration last to only use any unused memory + if (!population_table_load_bitfields( + data_specification_get_region(BIT_FIELD_FILTER_REGION, ds_regions))) { + return false; + } + + print_post_to_pre_entry(); + + log_debug("Initialise: finished"); + return true; +} + +//! \brief the function to call when resuming a simulation +void resume_callback(void) { + data_specification_metadata_t *ds_regions = + data_specification_get_data_address(); + + //! try resuming neuron + if (!neuron_resume( + data_specification_get_region(NEURON_PARAMS_REGION, ds_regions))) { + log_error("failed to resume neuron."); + rt_error(RTE_SWERR); + } + + // If the time has been reset to zero then the ring buffers need to be + // flushed in case there is a delayed spike left over from a previous run + // NOTE: at reset, time is set to UINT_MAX ahead of timer_callback(...) + if ((time+1) == 0) { + synapses_flush_ring_buffers(); + } + +} + +//! \brief Background activites called from timer +//! \param timer_count the number of times this call back has been +//! executed since start of simulation +//! \param[in] local_time: The time step being executed +void background_callback(uint timer_count, uint local_time) { + global_timer_count = timer_count; + profiler_write_entry_disable_irq_fiq(PROFILER_ENTER | PROFILER_TIMER); + + last_rewiring_time++; + + // This is the part where I save the input and output indices + // from the circular buffer + // If time == 0 as well as output == input == 0 then no rewire is + // supposed to happen. No spikes yet + log_debug("Timer tick %u \n", local_time); + + // Then do rewiring + + if (rewiring && + ((last_rewiring_time >= rewiring_period && !synaptogenesis_is_fast()) + || synaptogenesis_is_fast())) { + last_rewiring_time = 0; + // put flag in spike processing to do synaptic rewiring + if (synaptogenesis_is_fast()) { + spike_processing_do_rewiring(rewiring_period); + } else { + spike_processing_do_rewiring(1); + } + count_rewire_attempts++; + } + + + // Now do neuron time step update + neuron_do_timestep_update(local_time, timer_count); + + profiler_write_entry_disable_irq_fiq(PROFILER_EXIT | PROFILER_TIMER); + n_backgrounds_queued--; +} + +//! \brief Timer interrupt callback +//! \param[in] timer_count: the number of times this call back has been +//! executed since start of simulation +//! \param[in] unused: unused parameter kept for API consistency +void timer_callback(uint timer_count, UNUSED uint unused) { + // Disable interrupts to stop DMAs and MC getting in the way of this bit + uint32_t state = spin1_int_disable(); + + time++; + + // Clear any outstanding spikes + spike_processing_clear_input_buffer(time); + + spin1_mode_restore(state); + state = spin1_irq_disable(); + + // Also do synapses timestep update, as this is time-critical + synapses_do_timestep_update(time); + + /* if a fixed number of simulation ticks that were specified at startup + * then do reporting for finishing */ + if (simulation_is_finished()) { + + // Enter pause and resume state to avoid another tick + simulation_handle_pause_resume(resume_callback); + + log_debug("Completed a run"); + + // rewrite neuron params to SDRAM for reading out if needed + data_specification_metadata_t *ds_regions = + data_specification_get_data_address(); + neuron_pause(data_specification_get_region(NEURON_PARAMS_REGION, ds_regions)); + + profiler_write_entry_disable_irq_fiq(PROFILER_EXIT | PROFILER_TIMER); + + profiler_finalise(); + + // Subtract 1 from the time so this tick gets done again on the next + // run + time--; + + log_debug("Rewire tries = %d", count_rewire_attempts); + simulation_ready_to_read(); + spin1_mode_restore(state); + return; + } + + // Push the rest to the background + if (!spin1_schedule_callback(background_callback, timer_count, time, BACKGROUND)) { + // We have failed to do this timer tick! + n_background_overloads++; + } else { + n_backgrounds_queued++; + if (n_backgrounds_queued > max_backgrounds_queued) { + max_backgrounds_queued++; + } + } + + spin1_mode_restore(state); +} + +//! \brief The entry point for this model. +void c_main(void) { + + // initialise the model + if (!initialise()) { + rt_error(RTE_API); + } + + // Start the time at "-1" so that the first tick will be 0 + time = UINT32_MAX; + + // Set timer tick (in microseconds) + log_debug("setting timer tick callback for %d microseconds", timer_period); + spin1_set_timer_tick(timer_period); + + // Set up the timer tick callback (others are handled elsewhere) + spin1_callback_on(TIMER_TICK, timer_callback, TIMER); + + simulation_run(); +} diff --git a/neural_modelling/src/meanfield/direct_synapses.c b/neural_modelling/src/meanfield/direct_synapses.c new file mode 100644 index 00000000000..1f1db85780a --- /dev/null +++ b/neural_modelling/src/meanfield/direct_synapses.c @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2019-2020 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Implementation of direct_synapses.h +#include +#include +#include + +//! \brief The type of a singleton synaptic row. +//! \details The counts are constant. See ::synapse_row_plastic_part_t and +//! ::synapse_row_fixed_part_t for what this is a packed version of. +typedef struct single_synaptic_row_t { + const uint32_t n_plastic; //!< Number of plastic synapses. Always zero + const uint32_t n_fixed; //!< Number of fixed synapses. Always one + const uint32_t n_plastic_controls; //!< Number of plastic controls. Always zero + uint32_t synapse_datum; //!< The value of the single synapse +} single_synaptic_row_t; + +//! Working buffer for direct synapse access +static single_synaptic_row_t single_fixed_synapse = {0, 1, 0, 0}; + +//! The layout of the direct matrix region +typedef struct { + const uint32_t size; //!< Size of data, _not_ number of elements + const uint32_t data[]; //!< Direct matrix data +} direct_matrix_data_t; + +bool direct_synapses_initialise( + void *direct_matrix_address, address_t *direct_synapses_address) { + direct_matrix_data_t *direct_matrix = direct_matrix_address; + // Work out the positions of the direct and indirect synaptic matrices + // and copy the direct matrix to DTCM + uint32_t direct_matrix_size = direct_matrix->size; + log_info("Direct matrix malloc size is %d", direct_matrix_size); + + if (direct_matrix_size != 0) { + void *dtcm_copy = spin1_malloc(direct_matrix_size); + if (dtcm_copy == NULL) { + log_error("Not enough memory to allocate direct matrix"); + return false; + } + log_debug("Copying %u bytes of direct synapses to 0x%08x", + direct_matrix_size, dtcm_copy); + spin1_memcpy(dtcm_copy, direct_matrix->data, direct_matrix_size); + *direct_synapses_address = dtcm_copy; + } + + return true; +} + +synaptic_row_t direct_synapses_get_direct_synapse(void *row_address) { + uint32_t *data = row_address; + single_fixed_synapse.synapse_datum = *data; + return (synaptic_row_t) &single_fixed_synapse; +} diff --git a/neural_modelling/src/meanfield/direct_synapses.h b/neural_modelling/src/meanfield/direct_synapses.h new file mode 100644 index 00000000000..5ed75719933 --- /dev/null +++ b/neural_modelling/src/meanfield/direct_synapses.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2019-2020 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief API for accessing directly encoded synapses +#ifndef _DIRECT_SYNAPSES_H_ +#define _DIRECT_SYNAPSES_H_ + +//! \brief Setup for the direct synapses. +//! \param[in] direct_matrix_address: +//! the SDRAM base address for the direct matrix +//! \param[out] direct_synapses_address: +//! the DTCM address for the direct matrix +//! \return true if successful, false otherwise. +bool direct_synapses_initialise( + void *direct_matrix_address, address_t *direct_synapses_address); + +//! \brief Get the synapse for a given direct synaptic row. +//! \param[in] row_address: the row address to read. +//! \return the synaptic row synapse data. +synaptic_row_t direct_synapses_get_direct_synapse(void *row_address); + +#endif /* _DIRECT_SYNAPSES_H_ */ diff --git a/neural_modelling/src/meanfield/implementations/meanfield_impl.h b/neural_modelling/src/meanfield/implementations/meanfield_impl.h new file mode 100644 index 00000000000..9ccf0945b86 --- /dev/null +++ b/neural_modelling/src/meanfield/implementations/meanfield_impl.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \dir +//! \brief Neuron implementations +//! \file +//! \brief General API of a neuron implementation +#ifndef _MEANFIELD_IMPL_H_ +#define _MEANFIELD_IMPL_H_ + +#include + +//! \brief Initialise the particular implementation of the data +//! \param[in] n_neurons: The number of neurons +//! \return True if successful +static bool meanfield_impl_initialise(uint32_t n_meanfields); + +//! \brief Add inputs to the neuron +//! \param[in] synapse_type_index: the synapse type (e.g. exc. or inh.) +//! \param[in] neuron_index: the index of the neuron +//! \param[in] weights_this_timestep: weight inputs to be added +static void neuron_impl_add_inputs( + index_t synapse_type_index, index_t meanfield_index, + input_t weights_this_timestep); + +//! \brief Load in the neuron parameters +//! \param[in] address: SDRAM block to read parameters from +//! \param[in] next: Offset of next address in store +//! \param[in] n_neurons: The number of neurons +static void neuron_impl_load_neuron_parameters( + address_t address, uint32_t next, uint32_t n_meanfields); + +//! \brief Do the timestep update for the particular implementation +//! \param[in] neuron_index: The index of the neuron to update +//! \param[in] external_bias: External input to be applied to the neuron +//! \return True if a spike has occurred +static bool neuron_impl_do_timestep_update( + index_t meanfield_index, input_t external_bias); + +//! \brief Stores neuron parameters back into SDRAM +//! \param[out] address: the address in SDRAM to start the store +//! \param[in] next: Offset of next address in store +//! \param[in] n_neurons: The number of neurons +static void neuron_impl_store_neuron_parameters( + address_t address, uint32_t next, uint32_t n_meanfields); + +#if LOG_LEVEL >= LOG_DEBUG +//! \brief Print the inputs to the neurons +//! \param[in] n_neurons: The number of neurons +void neuron_impl_print_inputs(uint32_t n_meanfields); + +//! \brief Print the synapse parameters of the neurons +//! \param[in] n_neurons: The number of neurons +void neuron_impl_print_synapse_parameters(uint32_t n_meanfields); + +//! \brief Get the synapse type character for a synapse type +//! \param[in] synapse_type: The synapse type +//! \return The descriptor character (sometimes two characters) +const char *neuron_impl_get_synapse_type_char(uint32_t synapse_type); +#endif // LOG_LEVEL >= LOG_DEBUG + +#endif // _NEURON_IMPL_H_ diff --git a/neural_modelling/src/meanfield/implementations/meanfield_impl_standard.h b/neural_modelling/src/meanfield/implementations/meanfield_impl_standard.h new file mode 100644 index 00000000000..170771f6161 --- /dev/null +++ b/neural_modelling/src/meanfield/implementations/meanfield_impl_standard.h @@ -0,0 +1,479 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Inlined neuron implementation following standard component model +#ifndef _MEANFIELD_IMPL_STANDARD_H_ +#define _MEANFIELD_IMPL_STANDARD_H_ + +#include "meanfield_impl.h" +//#include + +// Includes for model parts used in this implementation +#include +#include +#include + +//#include + + +//#include +/*#include +#include +#include */ + +#include +#include +#include +#include + +// Further includes +#include + +//! Indices for recording of words +enum word_recording_indices { + //! V (somatic potential) recording index + V_RECORDING_INDEX = 0, + //! Gsyn_exc (excitatory synaptic conductance/current) recording index + GSYN_EXC_RECORDING_INDEX = 1, + //! Gsyn_inh (excitatory synaptic conductance/current) recording index + GSYN_INH_RECORDING_INDEX = 2, + //! Number of recorded word-sized state variables + N_RECORDED_VARS = 10 +}; + +//! Indices for recording of bitfields +enum bitfield_recording_indices { + //! Spike event recording index + SPIKE_RECORDING_BITFIELD = 0, + //! Number of recorded bitfields + N_BITFIELD_VARS = 1 +}; + +// This import depends on variables defined above +#include + +//! Array of meanfield states -> will be change in futur +static meanfield_t *meanfield_array; + +static config_t *config_array; + + +//! Input states array +static input_type_t *input_type_array; + +//! Additional input array +static additional_input_t *additional_input_array; + +//! Threshold states array +static threshold_type_t *threshold_type_array; + + +//! Global parameters for the neurons +static global_neuron_params_t *global_parameters; + +//! The synapse shaping parameters +static synapse_param_t *neuron_synapse_shaping_params; + +//! The number of steps to run per timestep +static uint n_steps_per_timestep; + +/*static inline void test(uint32_t time) { + for (uint32_t i = N_RECORDED_VARS; i > 0; i--) { + if (N_RECORDED_VARS==NULL){ + log_error("fail at %u", time); + } + } +}*/ + + +#ifndef SOMETIMES_UNUSED +#define SOMETIMES_UNUSED __attribute__((unused)) +#endif // !SOMETIMES_UNUSED + +SOMETIMES_UNUSED // Marked unused as only used sometimes +//! \brief Initialise the particular implementation of the data +//! \param[in] n_neurons: The number of neurons +//! \return True if successful +static bool meanfield_impl_initialise(uint32_t n_meanfields) { + // allocate DTCM for the global parameter details + if (sizeof(global_neuron_params_t)) { + global_parameters = spin1_malloc(sizeof(global_neuron_params_t)); + if (global_parameters == NULL) { + log_error("Unable to allocate global neuron parameters" + "- Out of DTCM"); + return false; + } + } + + // Allocate DTCM for neuron array + if (sizeof(meanfield_t)) { + meanfield_array = spin1_malloc(n_meanfields * sizeof(meanfield_t)); + if (meanfield_array == NULL) { + log_error("Unable to allocate meanfield array - Out of DTCM"); + return false; + } + } + + // Allocate DTCM for input type array and copy block of data + if (sizeof(config_t)) { + config_array = spin1_malloc(n_meanfields * sizeof(config_t)); + if (config_array == NULL) { + log_error("Unable to allocate config array - Out of DTCM"); + return false; + } + } + + // Allocate DTCM for input type array and copy block of data + if (sizeof(input_type_t)) { + input_type_array = spin1_malloc(n_meanfields * sizeof(input_type_t)); + if (input_type_array == NULL) { + log_error("Unable to allocate input type array - Out of DTCM"); + return false; + } + } + + // Allocate DTCM for additional input array and copy block of data + if (sizeof(additional_input_t)) { + additional_input_array = + spin1_malloc(n_meanfields * sizeof(additional_input_t)); + if (additional_input_array == NULL) { + log_error("Unable to allocate additional input array" + " - Out of DTCM"); + return false; + } + } + + // Allocate DTCM for threshold type array and copy block of data + if (sizeof(threshold_type_t)) { + threshold_type_array = + spin1_malloc(n_meanfields * sizeof(threshold_type_t)); + if (threshold_type_array == NULL) { + log_error("Unable to allocate threshold type array - Out of DTCM"); + return false; + } + } + + // Allocate DTCM for synapse shaping parameters + if (sizeof(synapse_param_t)) { + neuron_synapse_shaping_params = + spin1_malloc(n_meanfields * sizeof(synapse_param_t)); + if (neuron_synapse_shaping_params == NULL) { + log_error("Unable to allocate synapse parameters array" + " - Out of DTCM"); + return false; + } + } + + return true; +} + +SOMETIMES_UNUSED // Marked unused as only used sometimes +// \brief Will be used for communication btw MFs +//! \brief Add inputs to the neuron +//! \param[in] synapse_type_index: the synapse type (e.g. exc. or inh.) +//! \param[in] neuron_index: the index of the neuron +//! \param[in] weights_this_timestep: weight inputs to be added +static void neuron_impl_add_inputs( + index_t synapse_type_index, + index_t neuron_index, + input_t weights_this_timestep) { + // simple wrapper to synapse type input function + synapse_param_t *parameters = + &neuron_synapse_shaping_params[neuron_index]; + synapse_types_add_neuron_input(synapse_type_index, + parameters, weights_this_timestep); + +} + + +//! \brief The number of _words_ required to hold an object of given size +//! \param[in] size: The size of object +//! \return Number of words needed to hold the object (not bytes!) +static uint32_t n_words_needed(size_t size) { + return (size + (sizeof(uint32_t) - 1)) / sizeof(uint32_t); +} + +SOMETIMES_UNUSED // Marked unused as only used sometimes +//! \brief Load in the neuron parameters +//! \param[in] address: SDRAM block to read parameters from +//! \param[in] next: Offset of next address in store +//! \param[in] n_neurons: number of neurons +static void neuron_impl_load_neuron_parameters( + address_t address, uint32_t next, uint32_t n_meanfields) { + log_debug("reading parameters, next is %u, n_meanfields is %u ", + next, n_meanfields); + + // Read the number of steps per timestep + n_steps_per_timestep = address[next++]; + if (n_steps_per_timestep > 1) { + log_debug("Looping over %u steps each timestep", n_steps_per_timestep); + } else if (n_steps_per_timestep == 0) { + log_error("bad number of steps per timestep: 0"); + rt_error(RTE_SWERR); + } + + if (sizeof(global_neuron_params_t)) { + log_debug("writing neuron global parameters"); + spin1_memcpy(global_parameters, &address[next], + sizeof(global_neuron_params_t)); + next += n_words_needed(sizeof(global_neuron_params_t)); + } + + if (sizeof(meanfield_t)) { + log_debug("reading neuron local parameters"); + spin1_memcpy(meanfield_array, &address[next], + n_meanfields * sizeof(meanfield_t)); + next += n_words_needed(n_meanfields * sizeof(meanfield_t)); + } + + if (sizeof(config_t)) { + log_debug("reading input type parameters"); + spin1_memcpy(config_array, &address[next], + n_meanfields * sizeof(config_t)); + next += n_words_needed(n_meanfields * sizeof(config_t)); + } + + + meanfield_model_set_global_neuron_params(global_parameters); + +#if LOG_LEVEL >= LOG_DEBUG + log_debug("-------------------------------------\n"); + for (index_t n = 0; n < n_meanfields; n++) { + meanfield_model_print_parameters(&meanfield_array[n]); + } + log_debug("-------------------------------------\n"); +#endif // LOG_LEVEL >= LOG_DEBUG +} + +SOMETIMES_UNUSED // Marked unused as only used sometimes +//! \brief Do the timestep update for the particular implementation +//! \param[in] neuron_index: The index of the neuron to update +//! \param[in] external_bias: External input to be applied to the neuron +//! \return True if a spike has occurred +static bool neuron_impl_do_timestep_update(index_t meanfield_index, input_t external_bias){ + // Get the neuron itself + meanfield_t *this_meanfield = &meanfield_array[meanfield_index]; + + // Get the input_type parameters and voltage for this neuron + config_t *config_types = &config_array[meanfield_index]; + + mathsbox_t *mathsbox_types = &mathsbox_types[meanfield_index]; + + // Get the input_type parameters and voltage for this neuron + input_type_t *input_types = &input_type_array[meanfield_index]; + + // Get threshold and additional input parameters for this neuron + threshold_type_t *the_threshold_type = &threshold_type_array[meanfield_index]; + additional_input_t *additional_inputs = + &additional_input_array[meanfield_index]; + synapse_param_t *the_synapse_type = + &neuron_synapse_shaping_params[meanfield_index]; + + + // Store whether the neuron has spiked + bool has_spiked = false; + + // Loop however many times requested; do this in reverse for efficiency, + // and because the index doesn't actually matter + for (uint32_t i_step = n_steps_per_timestep; i_step > 0; i_step--) { + // Get the voltage->firing rate + state_t firing_rate = meanfield_model_get_firing_rate(this_meanfield); + + // Get the exc and inh values from the synapses + input_t exc_values[NUM_EXCITATORY_RECEPTORS]; + input_t *exc_syn_values = + synapse_types_get_excitatory_input(exc_values, the_synapse_type); + input_t inh_values[NUM_INHIBITORY_RECEPTORS]; + input_t *inh_syn_values = + synapse_types_get_inhibitory_input(inh_values, the_synapse_type); + + + // Call functions to obtain exc_input and inh_input + + input_t *exc_input_values = input_type_get_input_value( + exc_syn_values, input_types, NUM_EXCITATORY_RECEPTORS); + input_t *inh_input_values = input_type_get_input_value( + inh_syn_values, input_types, NUM_INHIBITORY_RECEPTORS); + + + // Sum g_syn contributions from all receptors for recording + + REAL total_exc = 0; + REAL total_inh = 0; + + for (int i = 0; i < NUM_EXCITATORY_RECEPTORS; i++) { + total_exc += exc_input_values[i]; + } + for (int i = 0; i < NUM_INHIBITORY_RECEPTORS; i++) { + total_inh += inh_input_values[i]; + } + + + // Do recording if on the first step + if (i_step == n_steps_per_timestep) { + neuron_recording_record_accum( + V_RECORDING_INDEX, meanfield_index, firing_rate); + + neuron_recording_record_accum( + GSYN_EXC_RECORDING_INDEX, meanfield_index, total_exc); + neuron_recording_record_accum( + GSYN_INH_RECORDING_INDEX, meanfield_index, total_inh); + + } + + // Call functions to convert exc_input and inh_input to current + input_type_convert_excitatory_input_to_current( + exc_input_values, input_types, firing_rate); + input_type_convert_inhibitory_input_to_current( + inh_input_values, input_types, firing_rate); + + external_bias += additional_input_get_input_value_as_current( + additional_inputs, firing_rate); + + + // update neuron parameters + state_t result = meanfield_model_state_update( + this_meanfield, config_types, mathsbox_types); + + //reinitialise Fout_th + config_types->Fout_th = 0.0; + + // determine if a spike should occur + + bool spike_now = + threshold_type_is_above_threshold(result, the_threshold_type); + + // If spike occurs, communicate to relevant parts of model + if (spike_now) { + has_spiked = true; + + // Call relevant model-based functions + // Tell the neuron model + neuron_model_has_spiked(this_meanfield); + + // Tell the additional input + additional_input_has_spiked(additional_inputs); + } + + + // Shape the existing input according to the included rule + synapse_types_shape_input(the_synapse_type); + if (config_types->Fout_th==0.0) { + has_spiked = true; + } + } + + + if (has_spiked) { + // Record the spike + neuron_recording_record_bit(SPIKE_RECORDING_BITFIELD, meanfield_index); + } + + +#if LOG_LEVEL >= LOG_DEBUG + meanfield_model_print_state_variables(this_meanfield); +#endif // LOG_LEVEL >= LOG_DEBUG + + // Return the boolean to the model timestep update + //return reinitialisation_Fout; + return has_spiked; +} + +SOMETIMES_UNUSED // Marked unused as only used sometimes +//! \brief Stores neuron parameters back into SDRAM +//! \param[out] address: the address in SDRAM to start the store +//! \param[in] next: Offset of next address in store +//! \param[in] n_neurons: number of neurons +static void neuron_impl_store_neuron_parameters( + address_t address, uint32_t next, uint32_t n_meanfields) { + log_debug("writing parameters"); + + // Skip over the steps per timestep + next += 1; + + if (sizeof(global_neuron_params_t)) { + log_debug("writing neuron global parameters"); + spin1_memcpy(&address[next], global_parameters, + sizeof(global_neuron_params_t)); + next += n_words_needed(sizeof(global_neuron_params_t)); + } + + if (sizeof(meanfield_t)) { + log_debug("writing neuron local parameters"); + spin1_memcpy(&address[next], meanfield_array, + n_meanfields * sizeof(meanfield_t)); + next += n_words_needed(n_meanfields * sizeof(meanfield_t)); + } + + if (sizeof(config_t)) { + log_debug("writing input type parameters"); + spin1_memcpy(&address[next], config_array, + n_meanfields * sizeof(config_t)); + next += n_words_needed(n_meanfields * sizeof(config_t)); + } + +} + +#if LOG_LEVEL >= LOG_DEBUG +//! \brief Print the inputs to the neurons +//! \param[in] n_neurons: The number of neurons +void neuron_impl_print_inputs(uint32_t n_neurons) { + bool empty = true; + for (index_t i = 0; i < n_neurons; i++) { + synapse_param_t *params = &neuron_synapse_shaping_params[i]; + empty = empty && (0 == bitsk( + synapse_types_get_excitatory_input(params) + - synapse_types_get_inhibitory_input(params))); + } + + if (!empty) { + log_debug("-------------------------------------\n"); + + for (index_t i = 0; i < n_neurons; i++) { + synapse_param_t *params = &neuron_synapse_shaping_params[i]; + input_t input = synapse_types_get_excitatory_input(params) + - synapse_types_get_inhibitory_input(params); + if (bitsk(input) != 0) { + log_debug("%3u: %12.6k (= ", i, input); + synapse_types_print_input(params); + log_debug(")\n"); + } + } + log_debug("-------------------------------------\n"); + } +} + +//! \brief Print the synapse parameters of the neurons +//! \param[in] n_neurons: The number of neurons +void neuron_impl_print_synapse_parameters(uint32_t n_neurons) { + log_debug("-------------------------------------\n"); + for (index_t n = 0; n < n_neurons; n++) { + synapse_types_print_parameters(&neuron_synapse_shaping_params[n]); + } + log_debug("-------------------------------------\n"); +} + +//! \brief Get the synapse type character for a synapse type +//! \param[in] synapse_type: The synapse type +//! \return The descriptor character (sometimes two characters) +const char *neuron_impl_get_synapse_type_char(uint32_t synapse_type) { + return synapse_types_get_type_char(synapse_type); +} +#endif // LOG_LEVEL >= LOG_DEBUG + +#endif // _NEURON_IMPL_STANDARD_H_ diff --git a/neural_modelling/src/meanfield/implementations/my_full_neuron_impl.h b/neural_modelling/src/meanfield/implementations/my_full_neuron_impl.h new file mode 100644 index 00000000000..05a16f94f33 --- /dev/null +++ b/neural_modelling/src/meanfield/implementations/my_full_neuron_impl.h @@ -0,0 +1,116 @@ +#ifndef _MY_FULL_NEURON_IMPL_ +#define _MY_FULL_NEURON_IMPL_ + +// Demonstrating that a "neuron model" can be defined in a different +// way without the use of components for additional input / input / threshold + +#include +#include +#include + +#define V_RECORDING_INDEX 0 +#define N_RECORDED_VARS 1 + +#define SPIKE_RECORDING_BITFIELD 0 +#define N_BITFIELD_VARS 1 + +#include + +//! neuron_impl_t struct +typedef struct neuron_impl_t { + accum inputs[2]; + accum v; + accum threshold; +} neuron_impl_t; + +//! Array of neuron states +static neuron_impl_t *neuron_array; + +__attribute__((unused)) // Marked unused as only used sometimes +static bool neuron_impl_initialise(uint32_t n_neurons) { + // Allocate DTCM for neuron array + if (sizeof(neuron_impl_t) != 0) { + neuron_array = spin1_malloc(n_neurons * sizeof(neuron_impl_t)); + if (neuron_array == NULL) { + log_error("Unable to allocate neuron array - Out of DTCM"); + return false; + } + } + + return true; +} + +__attribute__((unused)) // Marked unused as only used sometimes +static void neuron_impl_load_neuron_parameters( + address_t address, uint32_t next, uint32_t n_neurons) { + // Copy parameters to DTCM from SDRAM + spin1_memcpy(neuron_array, &address[next], + n_neurons * sizeof(neuron_impl_t)); +} + +__attribute__((unused)) // Marked unused as only used sometimes +static void neuron_impl_store_neuron_parameters( + address_t address, uint32_t next, uint32_t n_neurons) { + // Copy parameters to SDRAM from DTCM + spin1_memcpy(&address[next], neuron_array, + n_neurons * sizeof(neuron_impl_t)); +} + +__attribute__((unused)) // Marked unused as only used sometimes +static void neuron_impl_add_inputs( + index_t synapse_type_index, index_t neuron_index, + input_t weights_this_timestep) { + // Get the neuron itself + neuron_impl_t *neuron = &neuron_array[neuron_index]; + + // Do something to store the inputs for the next state update + neuron->inputs[synapse_type_index] += weights_this_timestep; +} + +__attribute__((unused)) // Marked unused as only used sometimes +static bool neuron_impl_do_timestep_update( + index_t neuron_index, input_t external_bias) { + // Get the neuron itself + neuron_impl_t *neuron = &neuron_array[neuron_index]; + + // Store the recorded membrane voltage + neuron_recording_record_accum(V_RECORDING_INDEX, neuron_index, neuron->v); + + // Do something to update the state + neuron->v += external_bias + neuron->inputs[0] - neuron->inputs[1]; + neuron->inputs[0] = 0; + neuron->inputs[1] = 0; + + // Determine if the neuron has spiked + if (neuron->v > neuron->threshold) { + // Reset if spiked + neuron->v = 0k; + neuron_recording_record_bit(SPIKE_RECORDING_BITFIELD, neuron_index); + return true; + } + return false; +} + +#if LOG_LEVEL >= LOG_DEBUG +void neuron_impl_print_inputs(uint32_t n_neurons) { + log_debug("-------------------------------------\n"); + for (index_t i = 0; i < n_neurons; i++) { + neuron_impl_t *neuron = &neuron_array[i]; + log_debug("inputs: %k %k", neuron->inputs[0], neuron->inputs[1]); + } + log_debug("-------------------------------------\n"); +} + +void neuron_impl_print_synapse_parameters(uint32_t n_neurons) { + // there aren't any accessible in this example + use(n_neurons); +} + +const char *neuron_impl_get_synapse_type_char(uint32_t synapse_type) { + use(synapse_type); + return 0; +} +#endif // LOG_LEVEL >= LOG_DEBUG + + +#endif // _MY_FULL_NEURON_IMPL_ diff --git a/neural_modelling/src/meanfield/implementations/my_neuron_impl_semd.h b/neural_modelling/src/meanfield/implementations/my_neuron_impl_semd.h new file mode 100644 index 00000000000..f2e354668aa --- /dev/null +++ b/neural_modelling/src/meanfield/implementations/my_neuron_impl_semd.h @@ -0,0 +1,281 @@ +#ifndef _NEURON_IMPL_SEMD_H_ +#define _NEURON_IMPL_SEMD_H_ + +#include + +// Includes for model parts used in this implementation +#include +#include +#include + +// Further includes +#include + +#define V_RECORDING_INDEX 0 +#define GSYN_EXC_RECORDING_INDEX 1 +#define GSYN_INH_RECORDING_INDEX 2 +#define N_RECORDED_VARS 3 + +#define SPIKE_RECORDING_BITFIELD 0 +#define N_BITFIELD_VARS 1 + +#include + +typedef struct input_type_current_semd_t { + // my_multiplicator + REAL my_multiplicator[NUM_INHIBITORY_RECEPTORS]; + + // previous input value + REAL my_inh_input_previous[NUM_INHIBITORY_RECEPTORS]; +} input_type_current_semd_t; + +#define SCALING_FACTOR 40.0k + +static input_type_current_semd_t *input_type_array; + +//! Array of neuron states +static neuron_pointer_t neuron_array; + +//! Threshold states array +static threshold_type_pointer_t threshold_type_array; + +// The synapse shaping parameters +static synapse_param_t *neuron_synapse_shaping_params; + +// The number of steps per timestep to run over +static uint32_t n_steps_per_timestep; + +__attribute__((unused)) // Marked unused as only used sometimes +static bool neuron_impl_initialise(uint32_t n_neurons) { + // Allocate DTCM for neuron array + neuron_array = spin1_malloc(n_neurons * sizeof(neuron_t)); + if (neuron_array == NULL) { + log_error("Unable to allocate neuron array - Out of DTCM"); + return false; + } + + // Allocate DTCM for input type array and copy block of data + input_type_array = + spin1_malloc(n_neurons * sizeof(input_type_current_semd_t)); + if (input_type_array == NULL) { + log_error("Unable to allocate input type array - Out of DTCM"); + return false; + } + + // Allocate DTCM for threshold type array and copy block of data + threshold_type_array = spin1_malloc(n_neurons * sizeof(threshold_type_t)); + if (threshold_type_array == NULL) { + log_error("Unable to allocate threshold type array - Out of DTCM"); + return false; + } + + // Allocate DTCM for synapse shaping parameters + neuron_synapse_shaping_params = + spin1_malloc(n_neurons * sizeof(synapse_param_t)); + if (neuron_synapse_shaping_params == NULL) { + log_error("Unable to allocate synapse parameters array" + " - Out of DTCM"); + return false; + } + + return true; +} + +__attribute__((unused)) // Marked unused as only used sometimes +static void neuron_impl_add_inputs( + index_t synapse_type_index, index_t neuron_index, + input_t weights_this_timestep) { + // simple wrapper to synapse type input function + synapse_param_t *parameters = &neuron_synapse_shaping_params[neuron_index]; + synapse_types_add_neuron_input(synapse_type_index, + parameters, weights_this_timestep); +} + +__attribute__((unused)) // Marked unused as only used sometimes +static void neuron_impl_load_neuron_parameters( + address_t address, uint32_t next, uint32_t n_neurons) { + log_debug("writing parameters, next is %u, n_neurons is %u ", + next, n_neurons); + n_steps_per_timestep = address[next]; + next += 1; + + log_debug("writing neuron local parameters"); + spin1_memcpy(neuron_array, &address[next], n_neurons * sizeof(neuron_t)); + next += (n_neurons * sizeof(neuron_t)) / 4; + + log_debug("writing input type parameters"); + spin1_memcpy(input_type_array, &address[next], + n_neurons * sizeof(input_type_current_semd_t)); + next += (n_neurons * sizeof(input_type_current_semd_t)) / 4; + + log_debug("writing threshold type parameters"); + spin1_memcpy(threshold_type_array, &address[next], + n_neurons * sizeof(threshold_type_t)); + next += (n_neurons * sizeof(threshold_type_t)) / 4; + + log_debug("writing synapse parameters"); + spin1_memcpy(neuron_synapse_shaping_params, &address[next], + n_neurons * sizeof(synapse_param_t)); +} + +__attribute__((unused)) // Marked unused as only used sometimes +static bool neuron_impl_do_timestep_update(index_t neuron_index, + input_t external_bias) { + // Get the neuron itself + neuron_pointer_t neuron = &neuron_array[neuron_index]; + + // Get the input_type parameters and voltage for this neuron + input_type_current_semd_t *input_type = &input_type_array[neuron_index]; + + // Get threshold synapse parameters for this neuron + threshold_type_pointer_t threshold_type = + &threshold_type_array[neuron_index]; + synapse_param_pointer_t synapse_type = + &neuron_synapse_shaping_params[neuron_index]; + + bool spike = false; + for (uint32_t i = n_steps_per_timestep; i > 0; i--) { + + // Get the voltage + state_t voltage = neuron_model_get_membrane_voltage(neuron); + + // Get the exc and inh values from the synapses + input_t exc_values[NUM_EXCITATORY_RECEPTORS]; + input_t* exc_input_values = + synapse_types_get_excitatory_input(exc_values, synapse_type); + input_t inh_values[NUM_INHIBITORY_RECEPTORS]; + input_t* inh_input_values = + synapse_types_get_inhibitory_input(inh_values, synapse_type); + + // Set the inhibitory my_multiplicator value + for (int i = 0; i < NUM_INHIBITORY_RECEPTORS; i++) { + if ((inh_input_values[i] >= 0.01) && + (input_type->my_multiplicator[i] == 0) && + (input_type->my_inh_input_previous[i] == 0)) { + input_type->my_multiplicator[i] = exc_input_values[i]; + } else if (inh_input_values[i] < 0.01) { + input_type->my_multiplicator[i] = 0; + } + input_type->my_inh_input_previous[i] = inh_input_values[i]; + } + + // Sum g_syn contributions from all receptors for recording + REAL total_exc = 0; + REAL total_inh = 0; + + for (int i = 0; i < NUM_EXCITATORY_RECEPTORS; i++) { + total_exc += exc_input_values[i]; + } + for (int i = 0; i < NUM_INHIBITORY_RECEPTORS; i++) { + total_inh += inh_input_values[i]; + } + + // Do recording if on first step + if (i == n_steps_per_timestep) { + neuron_recording_record_accum(V_RECORDING_INDEX, neuron_index, voltage); + neuron_recording_record_accum(GSYN_EXC_RECORDING_INDEX, neuron_index, total_exc); + neuron_recording_record_accum(GSYN_INH_RECORDING_INDEX, neuron_index, total_inh); + } + + // This changes inhibitory to excitatory input + for (int i = 0; i < NUM_INHIBITORY_RECEPTORS; i++) { + inh_input_values[i] = -inh_input_values[i] * SCALING_FACTOR + * input_type->my_multiplicator[i]; + } + + // update neuron parameters + state_t result = neuron_model_state_update( + NUM_EXCITATORY_RECEPTORS, exc_input_values, + NUM_INHIBITORY_RECEPTORS, inh_input_values, external_bias, neuron); + + // determine if a spike should occur + bool spike_now = threshold_type_is_above_threshold(result, threshold_type); + + // If spike occurs, communicate to relevant parts of model + if (spike_now) { + // Call relevant model-based functions + // Tell the neuron model + spike = true; + neuron_model_has_spiked(neuron); + } + + // Shape the existing input according to the included rule + synapse_types_shape_input(synapse_type); + } + + if (spike) { + neuron_recording_record_bit(SPIKE_RECORDING_BITFIELD, neuron_index); + } + + // Return the boolean to the model timestep update + return spike; +} + +//! \brief stores neuron parameter back into sdram +//! \param[in] address: the address in sdram to start the store +__attribute__((unused)) // Marked unused as only used sometimes +static void neuron_impl_store_neuron_parameters( + address_t address, uint32_t next, uint32_t n_neurons) { + log_debug("writing parameters"); + next += 1; + + log_debug("writing neuron local parameters"); + spin1_memcpy(&address[next], neuron_array, + n_neurons * sizeof(neuron_t)); + next += (n_neurons * sizeof(neuron_t)) / 4; + + log_debug("writing input type parameters"); + spin1_memcpy(&address[next], input_type_array, + n_neurons * sizeof(input_type_current_semd_t)); + next += (n_neurons * sizeof(input_type_current_semd_t)) / 4; + + log_debug("writing threshold type parameters"); + spin1_memcpy(&address[next], threshold_type_array, + n_neurons * sizeof(threshold_type_t)); + next += (n_neurons * sizeof(threshold_type_t)) / 4; + + log_debug("writing synapse parameters"); + spin1_memcpy(&address[next], neuron_synapse_shaping_params, + n_neurons * sizeof(synapse_param_t)); +} + +#if LOG_LEVEL >= LOG_DEBUG +void neuron_impl_print_inputs(uint32_t n_neurons) { + bool empty = true; + for (index_t i = 0; i < n_neurons; i++) { + empty = empty && (0 == bitsk( + synapse_types_get_excitatory_input(&neuron_synapse_shaping_params[i]) + - synapse_types_get_inhibitory_input(&neuron_synapse_shaping_params[i]))); + } + + if (!empty) { + log_debug("-------------------------------------\n"); + + for (index_t i = 0; i < n_neurons; i++) { + input_t input = + synapse_types_get_excitatory_input(&neuron_synapse_shaping_params[i]) + - synapse_types_get_inhibitory_input(&neuron_synapse_shaping_params[i]); + if (bitsk(input) != 0) { + log_debug("%3u: %12.6k (= ", i, input); + synapse_types_print_input(&neuron_synapse_shaping_params[i]); + log_debug(")\n"); + } + } + log_debug("-------------------------------------\n"); + } +} + +void neuron_impl_print_synapse_parameters(uint32_t n_neurons) { + log_debug("-------------------------------------\n"); + for (index_t n = 0; n < n_neurons; n++) { + synapse_types_print_parameters(&neuron_synapse_shaping_params[n]); + } + log_debug("-------------------------------------\n"); +} + +const char *neuron_impl_get_synapse_type_char(uint32_t synapse_type) { + return synapse_types_get_type_char(synapse_type); +} +#endif // LOG_LEVEL >= LOG_DEBUG + +#endif // _NEURON_IMPL_SEMD_H_ diff --git a/neural_modelling/src/meanfield/input_types/input_type.h b/neural_modelling/src/meanfield/input_types/input_type.h new file mode 100644 index 00000000000..7012f8e8557 --- /dev/null +++ b/neural_modelling/src/meanfield/input_types/input_type.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \dir +//! \brief Synaptic inputs +//! \file +//! \brief API for synaptic inputs (see also \ref src/neuron/synapse_types) +#ifndef _INPUT_TYPE_H_ +#define _INPUT_TYPE_H_ + +#ifndef NUM_EXCITATORY_RECEPTORS +//! \private +//! \brief The number of excitatory receptors. +//! \details It should be defined by a synapse shaping include. +#define NUM_EXCITATORY_RECEPTORS 1 +#error NUM_EXCITATORY_RECEPTORS was undefined. It should be defined by a synapse\ + shaping include +#endif + +#ifndef NUM_INHIBITORY_RECEPTORS +//! \private +//! \brief The number of inhibitory receptors. +//! \details It should be defined by a synapse shaping include. +#define NUM_INHIBITORY_RECEPTORS 1 +#error NUM_INHIBITORY_RECEPTORS was undefined. It should be defined by a synapse\ + shaping include +#endif + +#include + +// Forward declaration of the input type structure +struct input_type_t; +typedef struct input_type_t input_type_t; +//! Declaration of the input type pointer +typedef input_type_t *input_type_pointer_t; + +//! \brief Gets the actual input value. This allows any scaling to take place +//! \param[in,out] value: The array of the receptor-based values of the input +//! before scaling +//! \param[in] input_type: The input type pointer to the parameters +//! \param[in] num_receptors: The number of receptors. +//! The size of the \p value array. +//! \return Pointer to array of values of the receptor-based input after +//! scaling +static input_t *input_type_get_input_value( + input_t *restrict value, input_type_t *input_type, + uint16_t num_receptors); + +//! \brief Converts an excitatory input into an excitatory current +//! \param[in,out] exc_input: Pointer to array of excitatory inputs from +//! different receptors this timestep. Note that this will already have +//! been scaled by input_type_get_input_value() +//! \param[in] input_type: The input type pointer to the parameters +//! \param[in] membrane_voltage: The membrane voltage to use for the input +static void input_type_convert_excitatory_input_to_current( + input_t *restrict exc_input, const input_type_t *input_type, + state_t membrane_voltage); + +//! \brief Converts an inhibitory input into an inhibitory current +//! \param[in,out] inh_input: Pointer to array of inhibitory inputs from +//! different receptors this timestep. Note that this will already have +//! been scaled by input_type_get_input_value() +//! \param[in] input_type: The input type pointer to the parameters +//! \param[in] membrane_voltage: The membrane voltage to use for the input +static void input_type_convert_inhibitory_input_to_current( + input_t *restrict inh_input, const input_type_t *input_type, + state_t membrane_voltage); + +#endif // _INPUT_TYPE_H_ diff --git a/neural_modelling/src/meanfield/input_types/input_type_conductance.h b/neural_modelling/src/meanfield/input_types/input_type_conductance.h new file mode 100644 index 00000000000..d11a37ea3de --- /dev/null +++ b/neural_modelling/src/meanfield/input_types/input_type_conductance.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Input type is standard conductance-based model +#ifndef _INPUT_TYPE_CONDUCTANCE_H_ +#define _INPUT_TYPE_CONDUCTANCE_H_ + +#include "input_type.h" + +//! Conductance input parameters +typedef struct input_type_t { + //! reversal voltage - Excitatory [mV] + REAL V_rev_E; + //! reversal voltage - Inhibitory [mV] + REAL V_rev_I; +} input_type_t; + +//! \brief Gets the actual input value. This allows any scaling to take place +//! \param[in,out] value: The array of the receptor-based values of the input +//! before scaling +//! \param[in] input_type: The input type pointer to the parameters +//! \param[in] num_receptors: The number of receptors. +//! The size of the \p value array. +//! \return Pointer to array of values of the receptor-based input after +//! scaling +static inline input_t *input_type_get_input_value( + input_t *restrict value, UNUSED input_type_t *input_type, + uint16_t num_receptors) { + for (int i = 0; i < num_receptors; i++) { + value[i] = value[i] >> 10; + } + return &value[0]; +} + +//! \brief Converts an excitatory input into an excitatory current +//! \param[in,out] exc_input: Pointer to array of excitatory inputs from +//! different receptors this timestep. Note that this will already have +//! been scaled by input_type_get_input_value() +//! \param[in] input_type: The input type pointer to the parameters +//! \param[in] membrane_voltage: The membrane voltage to use for the input +static inline void input_type_convert_excitatory_input_to_current( + input_t *restrict exc_input, const input_type_t *input_type, + state_t membrane_voltage) { + for (int i=0; i < NUM_EXCITATORY_RECEPTORS; i++) { + exc_input[i] = exc_input[i] * + (input_type->V_rev_E - membrane_voltage); + } +} + +//! \brief Converts an inhibitory input into an inhibitory current +//! \param[in,out] inh_input: Pointer to array of inhibitory inputs from +//! different receptors this timestep. Note that this will already have +//! been scaled by input_type_get_input_value() +//! \param[in] input_type: The input type pointer to the parameters +//! \param[in] membrane_voltage: The membrane voltage to use for the input +static inline void input_type_convert_inhibitory_input_to_current( + input_t *restrict inh_input, const input_type_t *input_type, + state_t membrane_voltage) { + for (int i=0; i < NUM_INHIBITORY_RECEPTORS; i++) { + inh_input[i] = -inh_input[i] * + (input_type->V_rev_I - membrane_voltage); + } +} + +#endif // _INPUT_TYPE_CONDUCTANCE_H_ diff --git a/neural_modelling/src/meanfield/input_types/input_type_current.h b/neural_modelling/src/meanfield/input_types/input_type_current.h new file mode 100644 index 00000000000..3a2843175c5 --- /dev/null +++ b/neural_modelling/src/meanfield/input_types/input_type_current.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Input type is standard current-based model +#ifndef _INPUT_TYPE_CURRENT_H_ +#define _INPUT_TYPE_CURRENT_H_ + +#include "input_type.h" + +typedef struct input_type_t { +} input_type_t; + +//! Scaling factor (trivial!) for input currents +static const REAL INPUT_SCALE_FACTOR = ONE; + +//! \brief Gets the actual input value. This allows any scaling to take place +//! \param[in,out] value: The array of the receptor-based values of the input +//! before scaling +//! \param[in] input_type: The input type pointer to the parameters +//! \param[in] num_receptors: The number of receptors. +//! The size of the \p value array. +//! \return Pointer to array of values of the receptor-based input after +//! scaling +static inline input_t *input_type_get_input_value( + input_t *restrict value, UNUSED input_type_t *input_type, + uint16_t num_receptors) { + for (int i = 0; i < num_receptors; i++) { + value[i] = value[i] * INPUT_SCALE_FACTOR; + // NOTE: this will be edited in future to be + // multiplied by a real scaling factor + } + return &value[0]; +} + +//! \brief Converts an excitatory input into an excitatory current +//! \param[in,out] exc_input: Pointer to array of excitatory inputs from +//! different receptors this timestep. Note that this will already have +//! been scaled by input_type_get_input_value() +//! \param[in] input_type: The input type pointer to the parameters +//! \param[in] membrane_voltage: The membrane voltage to use for the input +static inline void input_type_convert_excitatory_input_to_current( + UNUSED input_t *restrict exc_input, + UNUSED const input_type_t *input_type, + UNUSED state_t membrane_voltage) { +} + +//! \brief Converts an inhibitory input into an inhibitory current +//! \param[in,out] inh_input: Pointer to array of inhibitory inputs from +//! different receptors this timestep. Note that this will already have +//! been scaled by input_type_get_input_value() +//! \param[in] input_type: The input type pointer to the parameters +//! \param[in] membrane_voltage: The membrane voltage to use for the input +static inline void input_type_convert_inhibitory_input_to_current( + UNUSED input_t *restrict inh_input, + UNUSED const input_type_t *input_type, + UNUSED state_t membrane_voltage) { +} + +#endif // _INPUT_TYPE_CURRENT_H_ diff --git a/neural_modelling/src/meanfield/input_types/input_type_delta.h b/neural_modelling/src/meanfield/input_types/input_type_delta.h new file mode 100644 index 00000000000..4dda931f67f --- /dev/null +++ b/neural_modelling/src/meanfield/input_types/input_type_delta.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Input type shaped as Dirac delta +#ifndef _INPUT_TYPE_DELTA_H_ +#define _INPUT_TYPE_DELTA_H_ + +#include "input_type.h" + +struct input_type_t { + // scale factor (1000.0 / timestep) + REAL scale_factor; +}; + +//! Scaling factor (trivial!) for input currents +static const REAL INPUT_SCALE_FACTOR = ONE; + +//! \brief Gets the actual input value. This allows any scaling to take place +//! \param[in,out] value: The array of the receptor-based values of the input +//! before scaling +//! \param[in] input_type: The input type pointer to the parameters +//! \param[in] num_receptors: The number of receptors. +//! The size of the \p value array. +//! \return Pointer to array of values of the receptor-based input after +//! scaling +static inline input_t *input_type_get_input_value( + input_t *restrict value, UNUSED input_type_t *input_type, + uint16_t num_receptors) { + for (int i = 0; i < num_receptors; i++) { + value[i] = value[i] * INPUT_SCALE_FACTOR; + } + return &value[0]; +} + +//! \brief Converts an excitatory input into an excitatory current +//! \param[in,out] exc_input: Pointer to array of excitatory inputs from +//! different receptors this timestep. Note that this will already have +//! been scaled by input_type_get_input_value() +//! \param[in] input_type: The input type pointer to the parameters +//! \param[in] membrane_voltage: The membrane voltage to use for the input +static inline void input_type_convert_excitatory_input_to_current( + input_t *restrict exc_input, const input_type_t *input_type, + UNUSED state_t membrane_voltage) { + for (int i=0; i < NUM_EXCITATORY_RECEPTORS; i++) { + exc_input[i] = exc_input[i] * input_type->scale_factor; + } +} + +//! \brief Converts an inhibitory input into an inhibitory current +//! \param[in,out] inh_input: Pointer to array of inhibitory inputs from +//! different receptors this timestep. Note that this will already have +//! been scaled by input_type_get_input_value() +//! \param[in] input_type: The input type pointer to the parameters +//! \param[in] membrane_voltage: The membrane voltage to use for the input +static inline void input_type_convert_inhibitory_input_to_current( + input_t *restrict inh_input, const input_type_t *input_type, + UNUSED state_t membrane_voltage) { + for (int i=0; i < NUM_INHIBITORY_RECEPTORS; i++) { + inh_input[i] = inh_input[i] * input_type->scale_factor; + } +} + +#endif // _INPUT_TYPE_DELTA_H_ diff --git a/neural_modelling/src/meanfield/input_types/input_type_none.h b/neural_modelling/src/meanfield/input_types/input_type_none.h new file mode 100644 index 00000000000..398fcf395bd --- /dev/null +++ b/neural_modelling/src/meanfield/input_types/input_type_none.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief The no-input input type +#ifndef _INPUT_TYPE_NONE_H_ +#define _INPUT_TYPE_NONE_H_ + +#ifndef NUM_EXCITATORY_RECEPTORS +//! No inputs, so no receptors +#define NUM_EXCITATORY_RECEPTORS 0 +#endif +#ifndef NUM_INHIBITORY_RECEPTORS +//! No inputs, so no receptors +#define NUM_INHIBITORY_RECEPTORS 0 +#endif + +#include "input_type.h" + +struct input_type_t { +}; + +//! \brief Gets the actual input value. This allows any scaling to take place +//! \details Actually does nothing; no receptors +//! \param[in,out] value: The array of the receptor-based values of the input +//! before scaling +//! \param[in] input_type: The input type pointer to the parameters +//! \param[in] num_receptors: The number of receptors. +//! The size of the \p value array. +//! \return Pointer to array of values of the receptor-based input after +//! scaling +static inline input_t *input_type_get_input_value( + UNUSED input_t *restrict value, UNUSED input_type_t *input_type, + UNUSED uint16_t num_receptors) { + return 0; +} + +//! \brief Converts an excitatory input into an excitatory current +//! \details Actually does nothing; no receptors +//! \param[in,out] exc_input: Pointer to array of excitatory inputs from +//! different receptors this timestep. Note that this will already have +//! been scaled by input_type_get_input_value() +//! \param[in] input_type: The input type pointer to the parameters +//! \param[in] membrane_voltage: The membrane voltage to use for the input +static inline void input_type_convert_excitatory_input_to_current( + UNUSED input_t *restrict exc_input, + UNUSED const input_type_t *input_type, + UNUSED state_t membrane_voltage) { +} + +//! \brief Converts an inhibitory input into an inhibitory current +//! \details Actually does nothing; no receptors +//! \param[in,out] inh_input: Pointer to array of inhibitory inputs from +//! different receptors this timestep. Note that this will already have +//! been scaled by input_type_get_input_value() +//! \param[in] input_type: The input type pointer to the parameters +//! \param[in] membrane_voltage: The membrane voltage to use for the input +static inline void input_type_convert_inhibitory_input_to_current( + UNUSED input_t *restrict inh_input, + UNUSED const input_type_t *input_type, + UNUSED state_t membrane_voltage) { +} + +#endif // _INPUT_TYPE_NONE_H_ diff --git a/neural_modelling/src/meanfield/input_types/my_input_type.h b/neural_modelling/src/meanfield/input_types/my_input_type.h new file mode 100644 index 00000000000..05cfdc2fd5d --- /dev/null +++ b/neural_modelling/src/meanfield/input_types/my_input_type.h @@ -0,0 +1,65 @@ +#ifndef _MY_INPUT_TYPE_H_ +#define _MY_INPUT_TYPE_H_ + +#ifndef NUM_EXCITATORY_RECEPTORS +#define NUM_EXCITATORY_RECEPTORS 1 +#error NUM_EXCITATORY_RECEPTORS was undefined. It should be defined by a synapse\ + shaping include +#endif + +#ifndef NUM_INHIBITORY_RECEPTORS +#define NUM_INHIBITORY_RECEPTORS 1 +#error NUM_INHIBITORY_RECEPTORS was undefined. It should be defined by a synapse\ + shaping include +#endif + +#include + +typedef struct input_type_t { + REAL multiplicator; + REAL my_parameter; +} input_type_t; + +static inline void _input_type_set_multiplicator_value( + input_t total, input_type_t *input_type) { + if (total > input_type->my_parameter) { + input_type->multiplicator = 1.0; + } else { + input_type->multiplicator += 1.0; + } +} + +static inline input_t *input_type_get_input_value( + input_t *restrict value, input_type_t *input_type, + uint16_t num_receptors) { + input_t total = 0.0; + for (uint32_t i = 0; i < num_receptors; i++) { + total += value[i]; + } + + _input_type_set_multiplicator_value(total, input_type); + + return &value[0]; +} + +static inline void input_type_convert_excitatory_input_to_current( + input_t *restrict exc_input, const input_type_t *input_type, + state_t membrane_voltage) { + use(membrane_voltage); + + for (uint32_t i=0; i < NUM_EXCITATORY_RECEPTORS; i++) { + exc_input[i] = exc_input[i] * input_type->multiplicator; + } +} + +static inline void input_type_convert_inhibitory_input_to_current( + input_t *restrict inh_input, const input_type_t *input_type, + state_t membrane_voltage) { + use(membrane_voltage); + + for (uint32_t i=0; i < NUM_INHIBITORY_RECEPTORS; i++) { + inh_input[i] = inh_input[i] * input_type->multiplicator; + } +} + +#endif // _MY_INPUT_TYPE_H_ diff --git a/neural_modelling/src/meanfield/meanfield.c b/neural_modelling/src/meanfield/meanfield.c new file mode 100644 index 00000000000..b2a721e648d --- /dev/null +++ b/neural_modelling/src/meanfield/meanfield.c @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/*! \file + * \brief implementation of the meanfield.h interface. + * come from neuron.h + * will change neuron for meanfield but for now need to see if it's work so + no change just necessary + * remove spikes and synapse because MF not need this. + * Will implemente synapse like connection btw MFs after 1MF will work + */ + +#include "meanfield.h" +//#include "implementations/meanfield_impl_standard.h" +#include "meanfield_recording.h" + +#include "implementations/meanfield_impl.h" + +#include "plasticity/synapse_dynamics.h" +#include +#include + +//! The key to be used for this core (will be ORed with neuron ID) +static key_t key; + +//! A checker that says if this model should be transmitting. If set to false +//! by the data region, then this model should not have a key. +static bool use_key; + +//! The number of neurons on the core +static uint32_t n_neurons; + +//! The recording flags +static uint32_t recording_flags = 0; + +//! parameters that reside in the neuron_parameter_data_region +struct neuron_parameters { + uint32_t has_key; + uint32_t transmission_key; + uint32_t n_neurons_to_simulate; + uint32_t n_synapse_types; + uint32_t incoming_spike_buffer_size; +}; + +//! Offset of start of global parameters, in words. +#define START_OF_GLOBAL_PARAMETERS \ + ((sizeof(struct neuron_parameters) + \ + sizeof(struct tdma_parameters)) / sizeof(uint32_t)) + +//! \brief does the memory copy for the neuron parameters +//! \param[in] address: the address where the neuron parameters are stored +//! in SDRAM +//! \return bool which is true if the mem copy's worked, false otherwise +static bool neuron_load_neuron_parameters(address_t address) { + log_debug("loading parameters"); + // call the neuron implementation functions to do the work + neuron_impl_load_neuron_parameters( + address, START_OF_GLOBAL_PARAMETERS, n_neurons); + return true; +} + +bool neuron_resume(address_t address) { // EXPORTED + if (!neuron_recording_reset(n_neurons)){ + log_error("failed to reload the neuron recording parameters"); + return false; + } + + log_debug("neuron_reloading_neuron_parameters: starting"); + return neuron_load_neuron_parameters(address); +} + +bool neuron_initialise( + address_t address, address_t recording_address, // EXPORTED + uint32_t *n_neurons_value, + uint32_t *n_synapse_types_value, + uint32_t *incoming_spike_buffer_size, + uint32_t *n_rec_regions_used) { + log_debug("neuron_initialise: starting"); + + /*static inline void test(uint32_t time) { + for (uint32_t i = N_RECORDED_VARS; i > 0; i--) { + if (N_RECORDED_VARS==NULL){ + log_error("fail at %u", n_neurons_value); + } + } + }*/ + + // init the TDMA + void *data_addr = address; + tdma_processing_initialise(&data_addr); + + // cast left over SDRAM into neuron struct. + struct neuron_parameters *params = data_addr; + + // Check if there is a key to use + use_key = params->has_key; + + // Read the spike key to use + key = params->transmission_key; + + // output if this model is expecting to transmit + if (!use_key) { + log_debug("\tThis model is not expecting to transmit as it has no key"); + } else { + log_debug("\tThis model is expected to transmit with key = %08x", key); + } + + // Read the neuron details + n_neurons = params->n_neurons_to_simulate; + *n_neurons_value = n_neurons; + *n_synapse_types_value = params->n_synapse_types; + + // Read the size of the incoming spike buffer to use + *incoming_spike_buffer_size = params->incoming_spike_buffer_size; + + log_debug("\t n_neurons = %u, spike buffer size = %u", n_neurons, + *incoming_spike_buffer_size); + + // Call the neuron implementation initialise function to setup DTCM etc. + if (!meanfield_impl_initialise(n_neurons)) { + return false; + } + + // load the data into the allocated DTCM spaces. + if (!neuron_load_neuron_parameters(address)) { + return false; + } + + // setup recording region + if (!neuron_recording_initialise( + recording_address, &recording_flags, n_neurons, n_rec_regions_used)) { + return false; + } + + return true; +} + +void neuron_pause(address_t address) { // EXPORTED + /* Finalise any recordings that are in progress, writing back the final + * amounts of samples recorded to SDRAM */ + if (recording_flags > 0) { + log_debug("updating recording regions"); + neuron_recording_finalise(); + } + + // call neuron implementation function to do the work + neuron_impl_store_neuron_parameters( + address, START_OF_GLOBAL_PARAMETERS, n_neurons); +} + +void neuron_do_timestep_update(timer_t time, uint timer_count) { // EXPORTED + + // the phase in this timer tick im in (not tied to neuron index) + tdma_processing_reset_phase(); + + // Prepare recording for the next timestep + neuron_recording_setup_for_next_recording(); + + // update each neuron individually + for (index_t neuron_index = 0; neuron_index < n_neurons; neuron_index++) { + + // Get external bias from any source of intrinsic plasticity + input_t external_bias = + synapse_dynamics_get_intrinsic_bias(time, neuron_index); + + // call the implementation function (boolean for spike) + bool spike = neuron_impl_do_timestep_update( + neuron_index, external_bias); + + // If the neuron has spiked + if (spike) { + log_debug("meanfield %u reinit at time %u", neuron_index, time); + + // Do any required synapse processing + synapse_dynamics_process_post_synaptic_event(time, neuron_index); + + if (use_key) { + tdma_processing_send_packet( + (key | neuron_index), 0, NO_PAYLOAD, timer_count); + } + } else { + log_debug("the neuron %d has been determined to not reinit", + neuron_index); + } + } + + log_debug("time left of the timer after tdma is %d", tc[T1_COUNT]); + + // Disable interrupts to avoid possible concurrent access + uint cpsr = spin1_int_disable(); + + // Record the recorded variables + neuron_recording_record(time); + + // Re-enable interrupts + spin1_mode_restore(cpsr); +} + +void neuron_add_inputs( // EXPORTED + index_t synapse_type_index, + index_t neuron_index, + input_t weights_this_timestep) { + neuron_impl_add_inputs(synapse_type_index, + neuron_index, weights_this_timestep); +} + +#if LOG_LEVEL >= LOG_DEBUG +void neuron_print_inputs(void) { // EXPORTED + neuron_impl_print_inputs(n_neurons); +} + +void neuron_print_synapse_parameters(void) { // EXPORTED + neuron_impl_print_synapse_parameters(n_neurons); +} + +const char *neuron_get_synapse_type_char(uint32_t n_neurons){//synapse_type) { // EXPORTED + return neuron_impl_get_synapse_type_char(synapse_type); +} +#endif // LOG_LEVEL >= LOG_DEBUG diff --git a/neural_modelling/src/meanfield/meanfield.h b/neural_modelling/src/meanfield/meanfield.h new file mode 100644 index 00000000000..a9b5e202681 --- /dev/null +++ b/neural_modelling/src/meanfield/meanfield.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/*! \file + * \brief interface for neurons + * + * The API contains: + * - neuron_initialise(): + * translate the data stored in the NEURON_PARAMS data region in SDRAM + * and converts it into C-based objects for use. + * - neuron_set_input_buffers(input_buffers_value): + * setter for the internal input buffers + * - neuron_do_timestep_update(): + * executes all the updates to neural parameters when a given timer + * period has occurred. + */ + +#ifndef _MEANFIELD_H_ +#define _MEANFIELD_H_ + +#include +#include + +//! \brief translate the data stored in the NEURON_PARAMS data region in SDRAM +//! and convert it into c based objects for use. +//! \param[in] address: the absolute address in SDRAM for the start of the +//! NEURON_PARAMS data region in SDRAM +//! \param[in] recording_address: the recording parameters in SDRAM +//! (contains which regions are active and how big they are) +//! \param[out] n_neurons_value: The number of neurons this model is to +//! simulate +//! \param[out] n_synapse_types_value: The number of synapse types in +//! the model +//! \param[out] incoming_spike_buffer_size: The number of spikes to +//! support in the incoming spike circular buffer +//! \param[out] n_rec_regions_used: The number of regions used by neuron recording +//! \return True if the translation was successful, otherwise False +bool neuron_initialise( + address_t address, address_t recording_address, uint32_t *n_neurons_value, + uint32_t *n_synapse_types_value, uint32_t *incoming_spike_buffer_size, + uint32_t *n_rec_regions_used); + +//! \brief executes all the updates to neural parameters when a given timer +//! period has occurred. +//! \param[in] time: the timer tick value currently being executed +//! \param[in] timer_count: used for detecting a wrapping timer +void neuron_do_timestep_update(timer_t time, uint timer_count); + +//! \brief Prepare to resume simulation of the neurons +//! \param[in] address: the address where the neuron parameters are stored +//! in SDRAM +//! \return bool which is true if the resume was successful or not +bool neuron_resume(address_t address); + +//! \brief Perform steps needed before pausing a simulation. +//! \details Stores neuron parameters back into SDRAM. +//! \param[in] address: the address where the neuron parameters are stored +//! in SDRAM +void neuron_pause(address_t address); + +//! \brief Add inputs to the neuron +//! \param[in] synapse_type_index the synapse type (e.g. exc. or inh.) +//! \param[in] neuron_index the index of the neuron +//! \param[in] weights_this_timestep weight inputs to be added +void neuron_add_inputs( + index_t synapse_type_index, index_t neuron_index, + input_t weights_this_timestep); + +#if LOG_LEVEL >= LOG_DEBUG +//! \brief Print the inputs to the neurons. +//! \details Only available in debug mode. +void neuron_print_inputs(void); + +//! \brief Print the neurons' synapse parameters. +//! \details Only available in debug mode. +void neuron_print_synapse_parameters(void); + +//! \brief Get the synapse _type_ description character. +//! \details Only available in debug mode. +//! \param[in] synapse_type: The synapse type. +//! \return a single character that describes the synapse. +const char *neuron_get_synapse_type_char(uint32_t synapse_type); +#endif + +#endif // _NEURON_H_ diff --git a/neural_modelling/src/meanfield/meanfield_recording.c b/neural_modelling/src/meanfield/meanfield_recording.c new file mode 100644 index 00000000000..cae80a334cd --- /dev/null +++ b/neural_modelling/src/meanfield/meanfield_recording.c @@ -0,0 +1,337 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Implementation of non-inlined API in neuron_recording.h +#include "meanfield_recording.h" + +#include +#include + +//! The index to record each variable to for each neuron +uint8_t **neuron_recording_indexes; + +//! The index to record each bitfield variable to for each neuron +uint8_t **bitfield_recording_indexes; + +//! An array of recording information structures +recording_info_t *recording_info; + +//! An array of bitfield information structures +bitfield_info_t *bitfield_info; + +//! An array of spaces into which recording values can be written +uint8_t **recording_values; + +//! An array of spaces into which bitfields can be written +uint32_t **bitfield_values; + +//! The number of recordings outstanding +volatile uint32_t n_recordings_outstanding = 0; + +//! The address of the recording region to read on reset +static void *reset_address; + +//! When bitwise anded with a number will floor to the nearest multiple of 4 +#define FLOOR_TO_4 0xFFFFFFFC + +//! Add to a number before applying floor to 4 to turn it into a ceil operation +#define CEIL_TO_4 3 + +//! \brief resets all states back to start state. +static void reset_record_counter(void) { + for (uint32_t i = 0; i < N_RECORDED_VARS; i++) { + if (recording_info[i].rate == 0) { + // Setting increment to zero means count will never equal rate + recording_info[i].increment = 0; + + // Count is not rate so does not record, but not 1 so it does not reset! + recording_info[i].count = 2; + } else { + // Increase one each call so count gets to rate + recording_info[i].increment = 1; + + // Using rate here so that the zero time is recorded + recording_info[i].count = recording_info[i].rate; + } + } + + // clear the bitfields + for (uint32_t i = 0; i < N_BITFIELD_VARS; i++) { + if (bitfield_info[i].rate == 0) { + // Setting increment to zero means count will never equal rate + bitfield_info[i].increment = 0; + + // Count is not rate so does not record, but not 1 so it does not reset! + bitfield_info[i].count = 2; + } else { + // Increase one each call so count gets to rate + bitfield_info[i].increment = 1; + + // Using rate here so that the zero time is recorded + bitfield_info[i].count = bitfield_info[i].rate; + clear_bit_field(bitfield_info[i].values->bits, + bitfield_info[i].n_words); + } + } +} + +//! \brief wrapper to recording finalise +void neuron_recording_finalise(void) { + recording_finalise(); +} + +//! \brief the number of bytes used in bitfield recording for n_neurons +//! \param[in] n_neurons: The number of neurons to create a bitfield for +//! \return the size of the bitfield data structure for the number of neurons +static inline uint32_t bitfield_data_size(uint32_t n_neurons) { + return sizeof(bitfield_values_t) + (get_bit_field_size(n_neurons) * sizeof(uint32_t)); +} + +//! \brief reads recording data from SDRAM +//! \param[in] recording_address: SDRAM location for the recording data +//! \param[in] n_neurons: the number of neurons to setup for +//! \return Whether the read was successful +static bool neuron_recording_read_in_elements( + void *recording_address, uint32_t n_neurons) { + // Round up the number of bytes to align at a word boundary i.e. round to + // the next multiple of 4 + uint32_t ceil_n_entries = (n_neurons + CEIL_TO_4) & FLOOR_TO_4; + + // GCC lets you define a struct like this! + typedef struct neuron_recording_data { + uint32_t rate; + uint32_t n_neurons_recording; + uint32_t element_size; + uint8_t indices[ceil_n_entries]; + } neuron_recording_data_t; + + neuron_recording_data_t *data = recording_address; + + for (uint32_t i = 0; i < N_RECORDED_VARS; i++) { + recording_info[i].rate = data[i].rate; + uint32_t n_neurons_rec = data[i].n_neurons_recording; + recording_info[i].element_size = data[i].element_size; + recording_info[i].size = sizeof(recording_values_t) + + (n_neurons_rec * recording_info[i].element_size); + // There is an extra "neuron" in the data used when one of the neurons + // is *not* recording, to avoid a check + uint32_t alloc_size = recording_info[i].size + + recording_info[i].element_size; + + // allocate memory for the recording + if (recording_info[i].values == NULL) { + recording_info[i].values = spin1_malloc(alloc_size); + if (recording_info[i].values == NULL) { + log_error("couldn't allocate recording data space for %d", i); + return false; + } + recording_values[i] = recording_info[i].values->data; + } + + // copy over the indexes + spin1_memcpy(neuron_recording_indexes[i], data[i].indices, + n_neurons * sizeof(uint8_t)); + } + + typedef struct bitfield_recording_data { + uint32_t rate; + uint32_t n_neurons_recording; + uint8_t indices[ceil_n_entries]; + } bitfield_recording_data_t; + + bitfield_recording_data_t *bitfield_data = + (bitfield_recording_data_t *) &data[N_RECORDED_VARS]; + + for (uint32_t i = 0; i < N_BITFIELD_VARS; i++) { + bitfield_info[i].rate = bitfield_data[i].rate; + uint32_t n_neurons_rec = bitfield_data[i].n_neurons_recording; + bitfield_info[i].size = bitfield_data_size(n_neurons_rec); + // There is an extra "neuron" in the data used when one of the neurons + // is *not* recording, to avoid a check + uint32_t alloc_size = bitfield_data_size(n_neurons_rec + 1); + + // allocate memory for the recording + if (bitfield_info[i].values == NULL) { + bitfield_info[i].values = spin1_malloc(alloc_size); + if (bitfield_info[i].values == NULL) { + log_error("couldn't allocate bitfield recording data space for %d", i); + return false; + } + // There is an extra "neuron" in the data used when one of the + // neurons is *not* recording, to avoid a check + bitfield_info[i].n_words = get_bit_field_size(n_neurons_rec + 1); + bitfield_values[i] = bitfield_info[i].values->bits; + } + + // copy over the indexes + spin1_memcpy(bitfield_recording_indexes[i], bitfield_data[i].indices, + n_neurons * sizeof(uint8_t)); + } + return true; +} + +bool neuron_recording_reset(uint32_t n_neurons) { + recording_reset(); + if (!neuron_recording_read_in_elements(reset_address, n_neurons)) { + log_error("failed to reread in the new elements after reset"); + return false; + } + return true; +} + +//! \brief handles all the DTCM allocations for recording words +//! \param[in] n_neurons: how many neurons to set DTCM for +//! \return True on success +static inline bool allocate_word_dtcm(uint32_t n_neurons) { + recording_info = spin1_malloc(N_RECORDED_VARS * sizeof(recording_info_t)); + if (recording_info == NULL) { + log_error("Could not allocated space for recording_info"); + return false; + } + + // allocate dtcm for the overall holder for indexes + neuron_recording_indexes = + spin1_malloc(N_RECORDED_VARS * sizeof(uint8_t *)); + if (neuron_recording_indexes == NULL) { + log_error("Could not allocate space for var_recording_indexes"); + return false; + } + + recording_values = spin1_malloc(N_RECORDED_VARS * sizeof(uint8_t *)); + if (recording_values == NULL) { + log_error("Could not allocate space for recording_values"); + return false; + } + + for (uint32_t i = 0; i < N_RECORDED_VARS; i++) { + // clear recorded values pointer + recording_info[i].values = NULL; + + // allocate dtcm for indexes for each recording region + neuron_recording_indexes[i] = spin1_malloc(n_neurons * sizeof(uint8_t)); + if (neuron_recording_indexes[i] == NULL) { + log_error("failed to allocate memory for recording index %d", i); + return false; + } + } + + // successfully allocated all DTCM. + return true; +} + +//! \brief handles all the DTCM allocations for recording bitfields +//! \param[in] n_neurons: how many neurons to set DTCM for +//! \return True on success +static inline bool allocate_bitfield_dtcm(uint32_t n_neurons) { + bitfield_info = spin1_malloc(N_BITFIELD_VARS * sizeof(bitfield_info_t)); + if (bitfield_info == NULL) { + log_error("Failed to allocate space for bitfield_info"); + return false; + } + + // allocate dtcm for the overall holder for indexes + bitfield_recording_indexes = + spin1_malloc(N_BITFIELD_VARS * sizeof(uint8_t *)); + if (bitfield_recording_indexes == NULL) { + log_error("Could not allocate space for bitfield_recording_indexes"); + return false; + } + + bitfield_values = spin1_malloc(N_BITFIELD_VARS * sizeof(uint32_t *)); + if (bitfield_values == NULL) { + log_error("Could not allocate space for bitfield_values"); + return false; + } + + for (uint32_t i = 0; i < N_BITFIELD_VARS; i++) { + // clear recorded values pointer + bitfield_info[i].values = NULL; + + // allocate dtcm for indexes for each recording region + bitfield_recording_indexes[i] = + spin1_malloc(n_neurons * sizeof(uint8_t)); + if (bitfield_recording_indexes[i] == NULL) { + log_error("failed to allocate memory for bitfield index %d", i); + return false; + } + } + + // successfully allocated all DTCM. + return true; +} + +//! The heading of the neuron recording region. +typedef struct neuron_recording_header { + //! The number of word-sized variables to record + uint32_t n_recorded_vars; + //! The number of bitfield variables to record + uint32_t n_bitfield_vars; +} neuron_recording_header_t; + +bool neuron_recording_initialise( + void *recording_address, uint32_t *recording_flags, + uint32_t n_neurons, uint32_t *n_rec_regions_used) { + // boot up the basic recording + void *data_addr = recording_address; + bool success = recording_initialize(&data_addr, recording_flags); + if (!success) { + log_error("failed to init basic recording."); + return false; + } + + // Verify the number of recording and bitfield elements + neuron_recording_header_t *header = data_addr; + if (header->n_recorded_vars != N_RECORDED_VARS) { + log_error("Data spec number of recording variables %d != " + "neuron implementation number of recorded variables %d", + header->n_recorded_vars, N_RECORDED_VARS); + return false; + } + if (header->n_bitfield_vars != N_BITFIELD_VARS) { + log_error("Data spec number of bitfield variables %d != " + "neuron implementation number of bitfield variables %d", + header->n_bitfield_vars, N_BITFIELD_VARS); + return false; + } + // Copy the number of regions used + *n_rec_regions_used = header->n_recorded_vars + header->n_bitfield_vars; + data_addr = &header[1]; + log_debug("Recording %d variables and %d bitfield variables", + N_RECORDED_VARS, N_BITFIELD_VARS); + + if (!allocate_word_dtcm(n_neurons)) { + log_error("failed to allocate DTCM for the neuron recording structs."); + return false; + } + if (!allocate_bitfield_dtcm(n_neurons)) { + log_error("failed to allocate DTCM for the bitfield recording structs"); + return false; + } + + // read in the sdram params into the allocated data objects + reset_address = data_addr; + if (!neuron_recording_read_in_elements(data_addr, n_neurons)) { + log_error("failed to read in the elements"); + return false; + } + + // reset stuff + reset_record_counter(); + + return true; +} diff --git a/neural_modelling/src/meanfield/meanfield_recording.h b/neural_modelling/src/meanfield/meanfield_recording.h new file mode 100644 index 00000000000..61b7b1f99f4 --- /dev/null +++ b/neural_modelling/src/meanfield/meanfield_recording.h @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2019-2020 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Recording of the state of a neuron (spiking, voltage, etc.) + +#ifndef _MEANFIELD_RECORDING_H_ +#define _MEANFIELD_RECORDING_H_ + +#include +#include +#include +#include + +//#include "implementations/meanfield_impl_standard.h" + + +//! A struct of the different types of recorded data +// Note data is just bytes here but actual type is used on writing +typedef struct recording_values_t { + uint32_t time; + uint8_t data[]; +} recording_values_t; + +//! A struct for bitfield data +typedef struct bitfield_values_t { + uint32_t time; + uint32_t bits[]; +} bitfield_values_t; + +//! A struct for information for a non-bitfield recording +typedef struct recording_info_t { + uint32_t element_size; + uint32_t rate; + uint32_t count; + uint32_t increment; + uint32_t size; + recording_values_t *values; +} recording_info_t; + +//! A struct for information on a bitfield recording +typedef struct bitfield_info_t { + uint32_t rate; + uint32_t count; + uint32_t increment; + uint32_t size; + uint32_t n_words; + bitfield_values_t *values; +} bitfield_info_t; + +//! The index to record each variable to for each neuron +extern uint8_t **neuron_recording_indexes; + +//! The index to record each bitfield variable to for each neuron +extern uint8_t **bitfield_recording_indexes; + +//! An array of recording information structures +extern recording_info_t *recording_info; + +//! An array of bitfield information structures +extern bitfield_info_t *bitfield_info; + +//! An array of spaces into which recording values can be written +extern uint8_t **recording_values; + +//! An array of spaces into which bitfields can be written +extern uint32_t **bitfield_values; + +//! \brief stores a recording of a value of any type, except bitfield; +//! use the functions below for common types as these will be faster. +//! \param[in] var_index: which recording variable to write this is +//! \param[in] neuron_index: the neuron id for this recorded data +//! \param[in] value: pointer to the value to record for this neuron. +static inline void neuron_recording_record_value( + uint32_t var_index, uint32_t neuron_index, void *value) { + uint32_t index = neuron_recording_indexes[var_index][neuron_index]; + uint32_t size = recording_info[var_index].element_size; + uint32_t p = size * index; + spin1_memcpy(&recording_values[var_index][p], value, size); +} + +//! \brief stores a recording of an accum variable only; this is faster than +//! neuron_recording_record_value for this type +//! \param[in] var_index: which recording variable to write this is +//! \param[in] neuron_index: the neuron id for this recorded data +//! \param[in] value: the results to record for this neuron. +static inline void neuron_recording_record_accum( + uint32_t var_index, uint32_t neuron_index, accum value) { + uint8_t index = neuron_recording_indexes[var_index][neuron_index]; + accum *data = (accum *) recording_values[var_index]; + data[index] = value; +} + +//! \brief stores a recording of a double variable only; this is faster than +//! neuron_recording_record_value for this type +//! \param[in] var_index: which recording variable to write this is +//! \param[in] neuron_index: the neuron id for this recorded data +//! \param[in] value: the results to record for this neuron. +static inline void neuron_recording_record_double( + uint32_t var_index, uint32_t neuron_index, double value) { + uint8_t index = neuron_recording_indexes[var_index][neuron_index]; + double *data = (double *) recording_values[var_index]; + data[index] = value; +} + +//! \brief stores a recording of a float variable only; this is faster than +//! neuron_recording_record_value for this type +//! \param[in] var_index: which recording variable to write this is +//! \param[in] neuron_index: the neuron id for this recorded data +//! \param[in] value: the results to record for this neuron. +static inline void neuron_recording_record_float( + uint32_t var_index, uint32_t neuron_index, float value) { + uint8_t index = neuron_recording_indexes[var_index][neuron_index]; + float *data = (float *) recording_values[var_index]; + data[index] = value; +} + +//! \brief stores a recording of an int32_t variable only; this is faster than +//! neuron_recording_record_value for this type +//! \param[in] var_index: which recording variable to write this is +//! \param[in] neuron_index: the neuron id for this recorded data +//! \param[in] value: the results to record for this neuron. +static inline void neuron_recording_record_int32( + uint32_t var_index, uint32_t neuron_index, int32_t value) { + uint8_t index = neuron_recording_indexes[var_index][neuron_index]; + int32_t *data = (int32_t *) recording_values[var_index]; + data[index] = value; +} + + +//! \brief stores a recording of a set bit; this is the only way to set a bit +//! in a bitfield; neuron_recording_record_value doesn't work for this! +//! \param[in] var_index: which bitfield recording variable to write this is +//! \param[in] neuron_index: which neuron to set the bit for +static inline void neuron_recording_record_bit( + uint32_t var_index, uint32_t neuron_index) { + // Record the bit + uint32_t index = neuron_recording_indexes[var_index][neuron_index]; + bit_field_set(bitfield_values[var_index], index); +} + +//! \brief does the recording process of handing over to basic recording +//! \param[in] time: the time to put into the recording stamps. +static inline void neuron_recording_record(uint32_t time) { + // go through all recordings + for (uint32_t i = N_RECORDED_VARS; i > 0; i--) { + recording_info_t *rec_info = &recording_info[i - 1]; + // if the rate says record, record now + if (rec_info->count == rec_info->rate) { + // Reset the count + rec_info->count = 1; + // Set the time and record the data + rec_info->values->time = time; + recording_record(i - 1, rec_info->values, rec_info->size); + } else { + + // Not recording this time, so increment by specified amount + rec_info->count += rec_info->increment; + } + } + + for (uint32_t i = N_BITFIELD_VARS; i > 0; i--) { + bitfield_info_t *bf_info = &bitfield_info[i - 1]; + // if the rate says record, record now + if (bf_info->count == bf_info->rate) { + // Reset the count + bf_info->count = 1; + // Skip empty bitfields + if (empty_bit_field(bf_info->values->bits, bf_info->n_words)) { + continue; + } + // Set the time and record the data (note index is after recorded_vars) + bf_info->values->time = time; + recording_record(i + N_RECORDED_VARS - 1, bf_info->values, bf_info->size); + } else { + + // Not recording this time, so increment by specified amount + bf_info->count += bf_info->increment; + } + } +} + +//! \brief sets up state for next recording. +static inline void neuron_recording_setup_for_next_recording(void) { + // Reset the bitfields before starting if a beginning of recording + for (uint32_t i = N_BITFIELD_VARS; i > 0; i--) { + bitfield_info_t *b_info = &bitfield_info[i - 1]; + if (b_info->count == 1) { + clear_bit_field(b_info->values->bits, b_info->n_words); + } + } +} + +//! \brief reads recording data from sdram on reset. +//! \param[in] n_neurons: the number of neurons to setup for +//! \return bool stating if the read was successful or not +bool neuron_recording_reset(uint32_t n_neurons); + +//! \brief sets up the recording stuff +//! \param[in] recording_address: sdram location for the recording data +//! \param[out] recording_flags: Output of flags which can be used to check if +//! a channel is enabled for recording +//! \param[in] n_neurons: the number of neurons to setup for +//! \param[out] n_rec_regions_used: Output the number of regions used by neuron +//! recording +//! \return bool stating if the init was successful or not +bool neuron_recording_initialise( + void *recording_address, uint32_t *recording_flags, + uint32_t n_neurons, uint32_t *n_rec_regions_used); + +//! \brief finishes recording +void neuron_recording_finalise(void); + +#endif //_NEURON_RECORDING_H_ diff --git a/neural_modelling/src/meanfield/models/config.h b/neural_modelling/src/meanfield/models/config.h new file mode 100644 index 00000000000..6c1d31e291d --- /dev/null +++ b/neural_modelling/src/meanfield/models/config.h @@ -0,0 +1,73 @@ +#ifndef _CONFIG_H_ +#define _CONFIG_H_ + +#include "meanfield_model.h" + + +/*struct config_t; +typedef struct config_t config_t; +typedef struct config_t* config_t;*/ + +typedef struct config_t { + // nominally 'fixed' parameters + REAL pconnec; + REAL Qe; + REAL Qi; + REAL Te; + REAL Ti; + REAL Ee; + REAL Ei; + REAL Ntot; + REAL gei; + REAL ext_drive; + REAL afferent_exc_fraction; + + REAL Gl; + REAL Cm; + REAL El; + + REAL P0; + REAL P1; + REAL P2; + REAL P3; + REAL P4; + REAL P5; + REAL P6; + REAL P7; + REAL P8; + REAL P9; + REAL P10; + + // Variable-state parameters + //REAL fe; + //REAL fi; + + REAL muV;//:=0.0; + REAL muV0; + //muV0 = -60e-3; + REAL DmuV0;// = 10e-3; + + REAL sV;//=0.0; + REAL sV0;// = 4e-3; + REAL DsV0;// = 6e-3; + + REAL muGn;//=0.0; + + REAL TvN;//=0.0; + REAL TvN0;// = 0.5; + REAL DTvN0;// = 1.; + + REAL Vthre;//=0.0; + + REAL Fout_th;//=0.0; +} config_t; + +/* +typedef struct global_toolbox_params_t { + REAL this_h; + REAL this_time; +} global_toolbox_params_t; +*/ + + +#endif \ No newline at end of file diff --git a/neural_modelling/src/meanfield/models/mathsbox.h b/neural_modelling/src/meanfield/models/mathsbox.h new file mode 100644 index 00000000000..098467e649e --- /dev/null +++ b/neural_modelling/src/meanfield/models/mathsbox.h @@ -0,0 +1,23 @@ +#ifndef _MATHSBOX_H_ +#define _MATHSBOX_H_ + +#include +#include +#include +//#include + + + +struct mathsbox_t; + +typedef struct mathsbox_t { + + REAL error_func_sample; + + REAL err_func; +}mathsbox_t; + +//typedef struct mathsbox_params_t* mathsbox_pointer_t; + +state_t error_function(REAL x, REAL factor, mathsbox_t *restrict mathsbox); +#endif \ No newline at end of file diff --git a/neural_modelling/src/meanfield/models/meanfield_model.h b/neural_modelling/src/meanfield/models/meanfield_model.h new file mode 100644 index 00000000000..7c65d7c4160 --- /dev/null +++ b/neural_modelling/src/meanfield/models/meanfield_model.h @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/*! + * \dir + * \brief Neuronal Soma Models. + * \file + * \brief The API for neuron models themselves. + */ + +#ifndef _MEANFIELD_MODEL_H_ +#define _MEANFIELD_MODEL_H_ + +#include + +//! Forward declaration of neuron type (creates a definition for a pointer to a +//! neuron parameter struct +struct meanfield_t; +typedef struct meanfield_t meanfield_t; +typedef struct meanfield_t* meanfield_pointer_t; + +struct config_t; +typedef struct config_t config_t; +typedef struct config_t* config_pointer_t; + +struct mathsbox_t; +typedef struct mathsbox_t mathsbox_t; +typedef struct mathsbox_t* mathsbox_pointer_t; + +//! Forward declaration of global neuron parameters +struct global_neuron_params_t; +typedef struct global_neuron_params_t global_neuron_params_t; +//! pointer to global neuron parameters +typedef global_neuron_params_t* global_neuron_params_pointer_t; + +//! \brief set the global neuron parameters +//! \param[in] params: The parameters to set +void meanfield_model_set_global_neuron_params( + const global_neuron_params_t *params); + +//! \brief primary function called in timer loop after synaptic updates +//! \param[in] num_excitatory_inputs: Number of excitatory receptor types. +//! \param[in] exc_input: Pointer to array of inputs per receptor type received +//! this timer tick that produce a positive reaction within the neuron in +//! terms of stimulation. +//! \param[in] num_inhibitory_inputs: Number of inhibitory receptor types. +//! \param[in] inh_input: Pointer to array of inputs per receptor type received +//! this timer tick that produce a negative reaction within the neuron in +//! terms of stimulation. +//! \param[in] external_bias: This is the intrinsic plasticity which could be +//! used for ac, noisy input etc etc. (general purpose input) +//! \param[in,out] neuron: the pointer to a neuron parameter struct which +//! contains all the parameters for a specific neuron +//! \return the value to be compared with a threshold value to determine if the +//! neuron has spiked +/* +state_t meanfield_model_state_update( + uint16_t num_excitatory_inputs, const input_t *exc_input, + uint16_t num_inhibitory_inputs, const input_t *inh_input, + input_t external_bias, meanfield_t *restrict meanfield, + config_t *restrict config); +*/ + + + +state_t meanfield_model_state_update( + meanfield_t *restrict meanfield, config_t *restrict config, mathsbox_t *restrict mathsbox); + +//! \brief Indicates that the neuron has spiked +//! \param[in, out] neuron pointer to a neuron parameter struct which contains +//! all the parameters for a specific neuron +void neuron_model_has_spiked(meanfield_t *restrict meanfield); + +//! \brief get the neuron membrane voltage for a given neuron parameter set +//! \param[in] neuron: a pointer to a neuron parameter struct which contains +//! all the parameters for a specific neuron +//! \return the membrane voltage for a given neuron with the neuron +//! parameters specified in neuron +state_t meanfield_model_get_firing_rate(const meanfield_t *meanfield); + +//! \brief printout of state variables i.e. those values that might change +//! \param[in] neuron: a pointer to a neuron parameter struct which contains all +//! the parameters for a specific neuron +void meanfield_model_print_state_variables(const meanfield_t *meanfield); + +//! \brief printout of parameters i.e. those values that don't change +//! \param[in] neuron: a pointer to a neuron parameter struct which contains all +//! the parameters for a specific neuron +void meanfield_model_print_parameters(const meanfield_t *meanfield); + +#endif // _NEURON_MODEL_H_ diff --git a/neural_modelling/src/meanfield/models/meanfield_model_impl.c b/neural_modelling/src/meanfield/models/meanfield_model_impl.c new file mode 100644 index 00000000000..c73ed4dab50 --- /dev/null +++ b/neural_modelling/src/meanfield/models/meanfield_model_impl.c @@ -0,0 +1,346 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Izhekevich neuron implementation +#include "meanfield_model_impl.h" +#include "mathsbox.h" +#include "config.h" + +#include + +//! The global parameters of the Izhekevich neuron model +static const global_neuron_params_t *global_params; + +/*! \brief For linear membrane voltages, 1.5 is the correct value. However + * with actual membrane voltage behaviour and tested over an wide range of + * use cases 1.85 gives slightly better spike timings. + */ +//static const REAL SIMPLE_TQ_OFFSET = REAL_CONST(1.85); +/* +///////////////////////////////////////////////////////////// +#if 0 +// definition for Izhikevich neuron +static inline void neuron_ode( + REAL t, REAL stateVar[], REAL dstateVar_dt[], + neuron_t *neuron, REAL input_this_timestep) { + REAL V_now = stateVar[1]; + REAL U_now = stateVar[2]; + log_debug(" sv1 %9.4k V %9.4k --- sv2 %9.4k U %9.4k\n", stateVar[1], + neuron->V, stateVar[2], neuron->U); + + // Update V + dstateVar_dt[1] = + REAL_CONST(140.0) + + (REAL_CONST(5.0) + REAL_CONST(0.0400) * V_now) * V_now - U_now + + input_this_timestep; + + // Update U + dstateVar_dt[2] = neuron->A * (neuron->B * V_now - U_now); +} +#endif +*/ + +//! \brief The original model uses 0.04, but this (1 ULP larger?) gives better +//! numeric stability. +//! +//! Thanks to Mantas Mikaitis for this! +//static const REAL MAGIC_MULTIPLIER = REAL_CONST(0.040008544921875); + + +/* #################################################################### + reuse of izk for meanfields + ################################################################### + */ + +state_t error_function( REAL x, REAL factor, mathsbox_t *restrict mathsbox){ +//devra coder fonction powerof + + REAL dt = x/mathsbox->error_func_sample; + REAL t; + REAL Pi = 3.1415927; + REAL Erfc=mathsbox->err_func; + for(t=0; t=x; t+=dt){ + Erfc += factor*(2/sqrtk(Pi))*expk(-(t*t)); + } + + return Erfc; + +} + + +state_t threshold_func(config_t *restrict config) +{ + /* + setting by default to True the square + because when use by external modules, coeff[5:]=np.zeros(3) + in the case of a linear threshold + */ + /*NEED TO AVOID DIVISION AS POSSIBLE + but not for now + */ + + config->muV0=-0.06; + config->DmuV0=0.01; + + config->sV0=0.004; + config->DsV0=0.006; + + config->TvN0=0.5; + config->DTvN0=1.; + + config->muV=0.; + config->sV=0.; + config->muGn=0.; + config->TvN=0.; + config->Vthre=0.; + config->Fout_th=0.; + + // + 0.\ //P4*np.log(muGn) + + config->Vthre = config->P0\ + + config->P1*(config->muV-config->muV0)/config->DmuV0\ + + config->P2*(config->sV-config->sV0)/config->DsV0\ + + config->P3*(config->TvN-config->TvN0)/config->DTvN0\ + + config->P5*((config->muV-config->muV0)/config->DmuV0)*((config->muV-config->muV0)/config->DmuV0)\ + + config->P6*((config->sV-config->sV0)/config->DsV0)*((config->sV-config->sV0)/config->DsV0)\ + + config->P7*((config->TvN-config->TvN0)/config->DTvN0)*((config->TvN-config->TvN0)/config->DTvN0)\ + + config->P8*(config->muV-config->muV0)/config->DmuV0*(config->sV-config->sV0)/config->DsV0\ + + config->P9*(config->muV-config->muV0)/config->DmuV0*(config->TvN-config->TvN0)/config->DTvN0\ + + config->P10*(config->sV-config->sV0)/config->DsV0*(config->TvN-config->TvN0)/config->DTvN0; + + return config->Vthre; + + } + + +state_t get_fluct_regime_varsup(REAL Ve, REAL Vi, config_t *restrict params) +{ + REAL Fe; + REAL Fi; + REAL muGe, muGi, muG; + REAL Ue, Ui; + REAL Tm, Tv; + + + // here TOTAL (sum over synapses) excitatory and inhibitory input + + Fe = Ve * (1.-params->gei)*params->pconnec*params->Ntot; // default is 1 !! + Fi = Vi * params->gei*params->pconnec*params->Ntot; + + muGe = params->Qe*params->Te*Ve; + muGi = params->Qi*params->Ti*Vi; + + muG = params->Gl+muGe+muGi; + + params->muV = (muGe*params->Ee+muGi*params->Ei+params->Gl*params->El)/muG; + params->muGn = muG/params->Gl; + + Tm = params->Cm/muG; + + Ue = params->Qe/muG*(params->Ee-params->muV); + Ui = params->Qi/muG*(params->Ei-params->muV); + + /*PENSEZ a enlever autant de division que possible*/ + + params->sV = sqrtk(Fe*(Ue*params->Te)*(Ue*params->Te)/2./(params->Te+Tm)+\ + Fi*(params->Ti*Ui)*(params->Ti*Ui)/2./(params->Ti+Tm)); + + if (params->sV < 1e-8){ + params->sV = 1e-8; + } + + if (Fe<1e-9)//just to insure a non zero division, + { + Fe += 1e-9; + } + else if (Fi<1e-9) + { + Fi += 1e-9; + } + + Tv = ( Fe*(Ue*params->Te)*(Ue*params->Te) + Fi*(params->Ti*Ui)*(params->Ti*Ui))\ + /(Fe*(Ue*params->Te)*(Ue*params->Te)/(params->Te+Tm)\ + + Fi*(params->Ti*Ui)*(params->Ti*Ui)/(params->Ti+Tm)); + + params->TvN = Tv*params->Gl/params->Cm; + + return params->muV;//, sV+1e-12, muGn, TvN +} + + +state_t TF(REAL Ve, REAL Vi, meanfield_t *meanfield, config_t *restrict config, mathsbox_t *restrict mathsbox){ + +/* argument are fe, fi and pseq_params + problem is to implement it with params and instruction coming from + DTCM and ITCM. + +*/ + REAL factor; + REAL argument; + + if (Ve < REAL_CONST(1e-8)){ + Ve = REAL_CONST(1e-8); + } + if (Vi < REAL_CONST(1e-8)){ + Vi = REAL_CONST(1e-8); + } + + get_fluct_regime_varsup(Ve, Vi, config); + threshold_func(config); + + if (config->sVsV = REAL_CONST(1e-4); + } + + factor = REAL_HALF(config->Gl/(config->TvN * config->Cm)); + argument = (config->Vthre - config->muV)/sqrtk(REAL_CONST(2.))/config->sV; + + config->Fout_th = error_function(factor, argument, mathsbox); + + if (config->Fout_th < REAL_CONST(1e-8)){ + config->Fout_th = REAL_CONST(1e-8); + } + + return config->Fout_th; +} + +void RK2_midpoint_MF(REAL h, meanfield_t *meanfield, config_t *restrict config, mathsbox_t *restrict mathsbox) { +/* need to input T_inv time scale where the 1/T will be done (and rounding) +on the user computer before send it to the DTCM. +*/ + REAL lastVe = meanfield->Ve; + REAL T_inv = meanfield->Timescale_inv; + + //configVe stand for TF1 i.e TF for exitatory pop. SO configVi is for TF2 + //In fact no configVe and configVi just config, all in the same file. + + + meanfield->Ve += lastVe\ + + REAL_HALF(TF(lastVe,1,meanfield, config, mathsbox) - lastVe)\ + *(REAL_CONST(2.0)-h)*h; + meanfield->Ve = meanfield->Ve * T_inv; +} + + +/*############################################################################## +end of reuse +################################################################################# +*/ + +/*! + * \brief Midpoint is best balance between speed and accuracy so far. + * \details From ODE solver comparison work, paper shows that Trapezoid version + * gives better accuracy at small speed cost + * \param[in] h: threshold + * \param[in,out] neuron: The model being updated + * \param[in] input_this_timestep: the input + */ +/*static inline void rk2_kernel_midpoint( + REAL h, neuron_t *neuron, REAL input_this_timestep) { + // to match Mathematica names + REAL lastV1 = neuron->V; + REAL lastU1 = neuron->U; + REAL a = neuron->A; + REAL b = neuron->B; + + REAL pre_alph = REAL_CONST(140.0) + input_this_timestep - lastU1; + REAL alpha = pre_alph + + (REAL_CONST(5.0) + MAGIC_MULTIPLIER * lastV1) * lastV1; + REAL eta = lastV1 + REAL_HALF(h * alpha); + + // could be represented as a long fract? + REAL beta = REAL_HALF(h * (b * lastV1 - lastU1) * a); + + neuron->V += h * (pre_alph - beta + + (REAL_CONST(5.0) + MAGIC_MULTIPLIER * eta) * eta); + + neuron->U += a * h * (-lastU1 - beta + b * eta); +} +*/ + + +void meanfield_model_set_global_neuron_params( + const global_neuron_params_t *params) { + global_params = params; +} + +/*perhaps when we will do more than one MF we could uses "num_excitatory_inputs" like the number of ex MF and in MF? + and maybe is there some contamanation from the neightbourest neighbour MF! +*/ +state_t meanfield_model_state_update( + meanfield_t *restrict meanfield, config_t *restrict config, mathsbox_t *restrict mathsbox){ + /* + uint16_t num_excitatory_inputs, const input_t *exc_input, + uint16_t num_inhibitory_inputs, const input_t *inh_input, + input_t external_bias, meanfield_t *restrict meanfield, + config_t *restrict config) { + REAL total_exc = 0; + REAL total_inh = 0; + + for (int i =0; iI_offset; + */ + + // the best AR update so far + RK2_midpoint_MF(meanfield->this_h, meanfield, config, mathsbox); + meanfield->this_h = global_params->machine_timestep_ms; + + return meanfield->Ve; +} + + + +void neuron_model_has_spiked(meanfield_t *restrict meanfield) { + log_debug("in neuron_model_has_spiked, time is ", + global_params->machine_timestep_ms); + // reset membrane voltage + //neuron->V = neuron->C; + + // offset 2nd state variable + //neuron->U += neuron->D; + + // simple threshold correction - next timestep (only) gets a bump + //neuron->this_h = global_params->machine_timestep_ms * SIMPLE_TQ_OFFSET; +} + +//change name neuron -> meanfield and membrane -> rate +state_t meanfield_model_get_firing_rate(const meanfield_t *meanfield) { + return meanfield->Ve; +} + +void meanfield_model_print_state_variables(const meanfield_t *meanfield) { + log_debug("Ve = %11.4k ", meanfield->Ve); + //log_debug("U = %11.4k ", meanfield->Vi); +} + +void meanfield_model_print_parameters(const meanfield_t *meanfield) { + log_debug("Ve = %11.4k ", meanfield->Ve); + //log_debug("Vi = %11.4k ", meanfield->Vi); + //log_debug("B = %11.4k ", neuron->B); + //log_debug("C = %11.4k ", neuron->C); + //log_debug("D = %11.4k ", neuron->D); + + //log_debug("I = %11.4k \n", neuron->I_offset); +} diff --git a/neural_modelling/src/meanfield/models/meanfield_model_impl.h b/neural_modelling/src/meanfield/models/meanfield_model_impl.h new file mode 100644 index 00000000000..d33294a39b5 --- /dev/null +++ b/neural_modelling/src/meanfield/models/meanfield_model_impl.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief meanfield types +#ifndef _MEANFIELD_MODEL_IMPL_H_ +#define _MEANFIELD_MODEL_IMPL_H_ + +#include "meanfield_model.h" + +typedef struct meanfield_t { + // TODO: Parameters - make sure these match with the Python code, + // including the order of the variables when returned by + // get_neural_parameters. + + // + REAL a; + REAL b; + REAL tauw; + REAL Trefrac; + REAL Vthre; + REAL Vreset; + REAL delta_v; + REAL ampnoise; + REAL Timescale_inv; + + REAL Ve; // will be used as a vector !!! OR Ve and Vi + //REAL Vi; + + //vector V = {Ve, Vi}; + + REAL this_h; + + +} meanfield_t; + +typedef struct global_neuron_params_t { + // TODO: Add any parameters that apply to the whole model here (i.e. not + // just to a single neuron) + + // Note: often these are not user supplied, but computed parameters + + //uint32_t machine_time_step; + REAL machine_timestep_ms; +} global_neuron_params_t; + +#endif // _NEURON_MODEL_MY_IMPL_H_ diff --git a/neural_modelling/src/meanfield/models/my_neuron_model_impl.c b/neural_modelling/src/meanfield/models/my_neuron_model_impl.c new file mode 100644 index 00000000000..62cee066253 --- /dev/null +++ b/neural_modelling/src/meanfield/models/my_neuron_model_impl.c @@ -0,0 +1,70 @@ +#include "my_neuron_model_impl.h" + +#include + +// The global parameters of this neuron model +static const global_neuron_params_t *global_params; + +void neuron_model_set_global_neuron_params( + const global_neuron_params_t *params) { + + // TODO: Store parameters as required + global_params = params; +} + +state_t neuron_model_state_update( + uint16_t num_excitatory_inputs, const input_t* exc_input, + uint16_t num_inhibitory_inputs, const input_t* inh_input, + input_t external_bias, neuron_t *restrict neuron) { + + // This takes the input and generates an input value, assumed to be a + // current. Note that the conversion to current from conductance is done + // outside of this function, so does not need to be repeated here. + + // Sum contributions from multiple inputs (if used) + REAL total_exc = 0; + REAL total_inh = 0; + for (uint32_t i = 0; i < num_excitatory_inputs; i++) { + total_exc += exc_input[i]; + } + for (uint32_t i = 0; i < num_inhibitory_inputs; i++) { + total_inh += inh_input[i]; + } + + input_t input_this_timestep = + total_exc - total_inh + external_bias + neuron->I_offset; + + // TODO: Solve your equation here + neuron->V += input_this_timestep; + + log_debug("TESTING TESTING V = %11.4k mv", neuron->V); + + // Return the state variable to be compared with the threshold value + // to determine if the neuron has spikes (commonly the membrane voltage) + // TODO: Update to return the correct variable + return neuron->V; +} + +state_t neuron_model_get_membrane_voltage(const neuron_t *neuron) { + + // TODO: Get the state value representing the membrane voltage + return neuron->V; +} + +void neuron_model_has_spiked(neuron_t *restrict neuron) { + + // TODO: Perform operations required to reset the state after a spike + neuron->V = neuron->my_parameter; +} + +void neuron_model_print_state_variables(const neuron_t *neuron) { + + // TODO: Print all state variables + log_debug("V = %11.4k mv", neuron->V); +} + +void neuron_model_print_parameters(const neuron_t *neuron) { + + // TODO: Print all neuron parameters + log_debug("my parameter = %11.4k mv", neuron->my_parameter); +} diff --git a/neural_modelling/src/meanfield/models/my_neuron_model_impl.h b/neural_modelling/src/meanfield/models/my_neuron_model_impl.h new file mode 100644 index 00000000000..7fcb9ccd27d --- /dev/null +++ b/neural_modelling/src/meanfield/models/my_neuron_model_impl.h @@ -0,0 +1,28 @@ +#ifndef _NEURON_MODEL_MY_IMPL_H_ +#define _NEURON_MODEL_MY_IMPL_H_ + +#include + +typedef struct neuron_t { + // TODO: Parameters - make sure these match with the Python code, + // including the order of the variables when returned by + // get_neural_parameters. + + // Variable-state parameters e.g. membrane voltage + REAL V; + // offset current [nA] + REAL I_offset; + // Put anything else you want to store per neuron + REAL my_parameter; +} neuron_t; + +typedef struct global_neuron_params_t { + // TODO: Add any parameters that apply to the whole model here (i.e. not + // just to a single neuron) + + // Note: often these are not user supplied, but computed parameters + + uint32_t machine_time_step; +} global_neuron_params_t; + +#endif // _NEURON_MODEL_MY_IMPL_H_ diff --git a/neural_modelling/src/meanfield/plasticity/stdp/maths.h b/neural_modelling/src/meanfield/plasticity/stdp/maths.h new file mode 100644 index 00000000000..5abfb034b3a --- /dev/null +++ b/neural_modelling/src/meanfield/plasticity/stdp/maths.h @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Support functions for STDP +#ifndef MATHS_H +#define MATHS_H + +// Standard includes +#include +#include +#include + +//--------------------------------------- +// Macros +//--------------------------------------- +//! \brief Minimum. Evaluates arguments twice +//! \param X: First value +//! \param Y: Second value +//! \return Minimum of two values +#define MIN(X, Y) ((X) < (Y) ? (X) : (Y)) +//! \brief Maximum. Evaluates arguments twice +//! \param X: First value +//! \param Y: Second value +//! \return Maximum of two values +#define MAX(X, Y) ((X) > (Y) ? (X) : (Y)) + +//! \brief Lookup Table of 16-bit integers. +//! +//! Will be padded to a word boundary at the end. +typedef struct int16_lut { + uint16_t size; //!< Number of entries in table + uint16_t shift; //!< Mapping from time to table index + int16_t values[]; //!< Table of actual values +} int16_lut; + +//--------------------------------------- +// Plasticity maths function inline implementation +//--------------------------------------- +//! \brief Copy a Lookup Table from SDRAM to DTCM, updating the address +//! \param[in,out] address: Pointer to the SDRAM address to copy from. This is +//! updated to point to the space after the structure. +//! \return A pointer to the copied lookup table, malloc'd in DTCM +static inline int16_lut *maths_copy_int16_lut(address_t *address) { + int16_lut *sdram_lut = (int16_lut *) *address; + uint32_t size = sizeof(int16_lut) + (sdram_lut->size * sizeof(int16_t)); + int16_lut *lut = spin1_malloc(size); + if (lut == NULL) { + log_error("Not enough space to allocate LUT. Try reducing the timestep," + " the number of neurons per core, or the tau value"); + rt_error(RTE_SWERR); + } + spin1_memcpy(lut, sdram_lut, size); + + // Pad to number of words (+ 1 for size / shift header) + const uint32_t num_words = (lut->size / 2) + (((lut->size & 1) != 0) ? 1 : 0); + *address += num_words + 1; + + return lut; +} + +//! \brief Get value from lookup table +//! \param[in] time: The time that we are mapping +//! \param[in] lut: The lookup table (result of maths_copy_int16_lut()) +//! \return The value from the LUT, or zero if out of range +static inline int32_t maths_lut_exponential_decay( + uint32_t time, const int16_lut *lut) { + // Calculate lut index + uint32_t lut_index = time >> lut->shift; + + // Return value from LUT + return (lut_index < lut->size) ? lut->values[lut_index] : 0; +} + +//! \brief Clamp to fit in number of bits +//! \param[in] x: The value to clamp +//! \param[in] shift: Width of the field to clamp the value to fit in +//! \return The clamped value +static inline int32_t maths_clamp_pot(int32_t x, uint32_t shift) { + uint32_t y = x >> shift; + if (y) { + x = ~y >> (32 - shift); + } + + return x; +} + +//--------------------------------------- +//! \brief multiply two 16-bit numbers to get a 32-bit number. +//! +//! **NOTE:** this should 'encourage' GCC to insert SMULxy 16x16 multiply +//! +//! \param[in] x: The first multiplicand +//! \param[in] y: The first multiplicand +//! \return The product +static inline int32_t maths_mul_16x16(int16_t x, int16_t y) { + return x * y; +} + +//--------------------------------------- +//! \brief multiply two 16-bit fixed point numbers (encoded in int32_t) +//! \param[in] a: The first multiplicand +//! \param[in] b: The first multiplicand +//! \param[in] fixed_point_position: The location of the fixed point +//! \return The product +static inline int32_t maths_fixed_mul16( + int32_t a, int32_t b, const int32_t fixed_point_position) { + // Multiply lower 16-bits of a and b together + int32_t mul = __smulbb(a, b); + + // Shift down + return (mul >> fixed_point_position); +} + +//--------------------------------------- +//! \brief multiply two 32-bit fixed point numbers (encoded in int32_t) +//! \param[in] a: The first multiplicand +//! \param[in] b: The first multiplicand +//! \param[in] fixed_point_position: The location of the fixed point +//! \return The product +static inline int32_t maths_fixed_mul32( + int32_t a, int32_t b, const int32_t fixed_point_position) { + int32_t mul = a * b; + + // Shift down and return + return (mul >> fixed_point_position); +} + +#endif // MATHS_H diff --git a/neural_modelling/src/meanfield/plasticity/stdp/post_events.h b/neural_modelling/src/meanfield/plasticity/stdp/post_events.h new file mode 100644 index 00000000000..5d2b0cd743e --- /dev/null +++ b/neural_modelling/src/meanfield/plasticity/stdp/post_events.h @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Post-synaptic events +#ifndef _POST_EVENTS_H_ +#define _POST_EVENTS_H_ + +// Standard includes +#include +#include + +// Include debug header for log_info etc +#include + +//--------------------------------------- +// Macros +//--------------------------------------- +//! Maximum number of post-synaptic events supported +#define MAX_POST_SYNAPTIC_EVENTS 16 + +//--------------------------------------- +// Structures +//--------------------------------------- +//! Trace history of post-synaptic events +typedef struct { + //! Number of events stored (minus one) + uint32_t count_minus_one; + //! Event times + uint32_t times[MAX_POST_SYNAPTIC_EVENTS]; + //! Event traces + post_trace_t traces[MAX_POST_SYNAPTIC_EVENTS]; +} post_event_history_t; + +//! Post event window description +typedef struct { + //! The previous post-synaptic event trace + post_trace_t prev_trace; + //! The previous post-synaptic event time + uint32_t prev_time; + //! The next post-synaptic event trace + const post_trace_t *next_trace; + //! The next post-synaptic event time + const uint32_t *next_time; + //! The number of events + uint32_t num_events; + //! Whether the previous post-synaptic event is valid (based on time) + uint32_t prev_time_valid; +} post_event_window_t; + +//--------------------------------------- +// Inline functions +//--------------------------------------- + +//! \brief Print a post-synaptic event history +//! \param[in] events: The history +static inline void print_event_history(const post_event_history_t *events) { + log_info(" ## printing entire post event history ##"); + for (uint32_t i = 0; i <= events->count_minus_one; i++) { + log_info("post event: %u, time: %u, trace: %u", + i, events->times[i], events->traces[i]); + } +} + +//! \brief Initialise an array of post-synaptic event histories +//! \param[in] n_neurons: Number of neurons +//! \return The array +static inline post_event_history_t *post_events_init_buffers( + uint32_t n_neurons) { + post_event_history_t *post_event_history = + spin1_malloc(n_neurons * sizeof(post_event_history_t)); + // Check allocations succeeded + if (post_event_history == NULL) { + log_error("Unable to allocate global STDP structures - Out of DTCM: Try " + "reducing the number of neurons per core to fix this problem "); + return NULL; + } + + // Loop through neurons + for (uint32_t n = 0; n < n_neurons; n++) { + // Add initial placeholder entry to buffer + post_event_history[n].times[0] = 0; + post_event_history[n].traces[0] = timing_get_initial_post_trace(); + post_event_history[n].count_minus_one = 0; + } + + return post_event_history; +} + +//--------------------------------------- +//! \brief Get the post-synaptic event window +//! \param[in] events: The post-synaptic event history +//! \param[in] begin_time: The start of the window +//! \param[in] end_time: The end of the window +//! \return The window +static inline post_event_window_t post_events_get_window_delayed( + const post_event_history_t *events, uint32_t begin_time, + uint32_t end_time) { + // Start at end event - beyond end of post-event history + const uint32_t count = events->count_minus_one + 1; + const uint32_t *end_event_time = events->times + count; + const uint32_t *event_time = end_event_time; + const post_trace_t *event_trace = events->traces + count; + + post_event_window_t window; + do { + // If this event is still in the future, set it as the end + if (*event_time > end_time) { + end_event_time = event_time; + } + + // Cache pointer to this event as potential next event and go back one + // event. + // **NOTE** next_time can be invalid + window.next_time = event_time--; + window.next_trace = event_trace--; + + // Keep looping while event occurred after start of window and we + // haven't hit beginning of array... + } while (*event_time > begin_time && event_time != events->times); + + // Deference event to use as previous + window.prev_time = *event_time; + window.prev_trace = *event_trace; + window.prev_time_valid = event_time != events->times; + + // Calculate number of events + window.num_events = (end_event_time - window.next_time); + + // Return window + return window; +} + +//--------------------------------------- +//! \brief Advance a post-synaptic event window to the next event +//! \param[in] window: The window to advance +//! \return the advanced window +static inline post_event_window_t post_events_next( + post_event_window_t window) { + // Update previous time and increment next time + window.prev_time = *window.next_time++; + window.prev_trace = *window.next_trace++; + + // Time will now be valid for sure! + window.prev_time_valid = 1; + + // Decrement remaining events + window.num_events--; + return window; +} + +//--------------------------------------- +//! \brief Add a post-synaptic event to the history +//! \param[in] time: the time of the event +//! \param[in,out] events: the history to add to +//! \param[in] trace: the trace of the event +static inline void post_events_add( + uint32_t time, post_event_history_t *events, post_trace_t trace) { + if (events->count_minus_one < MAX_POST_SYNAPTIC_EVENTS - 1) { + // If there's still space, store time at current end + // and increment count minus 1 + const uint32_t new_index = ++events->count_minus_one; + events->times[new_index] = time; + events->traces[new_index] = trace; + } else { + // Otherwise Shuffle down elements + // **NOTE** 1st element is always an entry at time 0 + for (uint32_t e = 2; e < MAX_POST_SYNAPTIC_EVENTS; e++) { + events->times[e - 1] = events->times[e]; + events->traces[e - 1] = events->traces[e]; + } + + // Stick new time at end + events->times[MAX_POST_SYNAPTIC_EVENTS - 1] = time; + events->traces[MAX_POST_SYNAPTIC_EVENTS - 1] = trace; + } +} + +//! \brief Print the post-synaptic event history +//! \param[in] post_event_history: the history +//! \param[in] begin_time: The start time of the history +//! \param[in] end_time: The end time of the history +//! \param[in] delay_dendritic: The amount of dendritic delay +static inline void print_delayed_window_events( + const post_event_history_t *post_event_history, + uint32_t begin_time, uint32_t end_time, uint32_t delay_dendritic) { + log_info(" ## printing post window ##"); + post_event_window_t post_window = post_events_get_window_delayed( + post_event_history, begin_time, end_time); + + while (post_window.num_events > 0) { + const uint32_t delayed_post_time = + *post_window.next_time + delay_dendritic; + log_info("post spike: %u, time: %u, trace: %u", + post_window.num_events, delayed_post_time, + *post_window.next_trace); + + post_window = post_events_next(post_window); + } +} + +#endif // _POST_EVENTS_H_ diff --git a/neural_modelling/src/meanfield/plasticity/stdp/stdp_typedefs.h b/neural_modelling/src/meanfield/plasticity/stdp/stdp_typedefs.h new file mode 100644 index 00000000000..0425175c71d --- /dev/null +++ b/neural_modelling/src/meanfield/plasticity/stdp/stdp_typedefs.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \dir +//! \brief Spike Timing Dependent Plasticity (STDP) +//! \file +//! \brief Basic definitions for STDP +#ifndef _STDP_TYPEDEFS_H_ +#define _STDP_TYPEDEFS_H_ + +//--------------------------------------- +// Macros +//--------------------------------------- +// Fixed-point number system used STDP +//! Position of the point in the fixed point math used by STDP +#define STDP_FIXED_POINT 11 +//! The number 1.0 in the fixed point math used by STDP +#define STDP_FIXED_POINT_ONE (1 << STDP_FIXED_POINT) + +// Helper macros for 16-bit fixed-point multiplication +//! \brief Multiply two STDP fixed point numbers +//! \param[in] a: The first multiplicand +//! \param[in] b: The second multiplicand +//! \return The product +#define STDP_FIXED_MUL_16X16(a, b) maths_fixed_mul16(a, b, STDP_FIXED_POINT) + +#endif // _STDP_TYPEDEFS_H_ diff --git a/neural_modelling/src/meanfield/plasticity/stdp/synapse_structure/synapse_structure.h b/neural_modelling/src/meanfield/plasticity/stdp/synapse_structure/synapse_structure.h new file mode 100644 index 00000000000..2c4c23c2625 --- /dev/null +++ b/neural_modelling/src/meanfield/plasticity/stdp/synapse_structure/synapse_structure.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \dir +//! \brief Synaptic state management +//! \file +//! \brief API for synaptic state +//! +//! Implementations of this have one or more of: +//! * weight +//! * state +//! * accumulator +//! * event window +#ifndef _SYNAPSE_STRUCTURE_H_ +#define _SYNAPSE_STRUCTURE_H_ + +#include + +//! \brief Get the update state from the synapse structure +//! \param[in] synaptic_word: The plastic synapse data +//! \param[in] synapse_type: What (supported) type of synapse is this? +//! \return The update state +static update_state_t synapse_structure_get_update_state( + plastic_synapse_t synaptic_word, index_t synapse_type); + +//! \brief Get the final state from the update state. +//! \param[in] state: the update state +//! \return the final state +static final_state_t synapse_structure_get_final_state( + update_state_t state); + +//! \brief Get the final weight from the final state +//! \param[in] final_state: the final state +//! \return the final weight +static weight_t synapse_structure_get_final_weight( + final_state_t final_state); + +//! \brief Get the final plastic synapse data from the final state +//! \param[in] final_state: the final state +//! \return the final plastic synapse data, ready to be stored +static plastic_synapse_t synapse_structure_get_final_synaptic_word( + final_state_t final_state); + +//! \brief Create the initial plastic synapse data +//! \param[in] weight: the initial synaptic weight +//! \return the plastic synapse data +static plastic_synapse_t synapse_structure_create_synapse(weight_t weight); + +//! \brief Get the current synaptic weight from the plastic synapse data +//! \param[in] synaptic_word: the plastic synapse data +//! \return the current synaptic weight +static weight_t synapse_structure_get_weight(plastic_synapse_t synaptic_word); + +#endif // _SYNAPSE_STRUCTURE_H_ diff --git a/neural_modelling/src/meanfield/plasticity/stdp/synapse_structure/synapse_structure_weight_accumulator_impl.h b/neural_modelling/src/meanfield/plasticity/stdp/synapse_structure/synapse_structure_weight_accumulator_impl.h new file mode 100644 index 00000000000..023a95109c5 --- /dev/null +++ b/neural_modelling/src/meanfield/plasticity/stdp/synapse_structure/synapse_structure_weight_accumulator_impl.h @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Synapses made of weight and accumulator +#ifndef _SYNAPSE_STRUCUTRE_WEIGHT_STATE_ACCUMULATOR_IMPL_H_ +#define _SYNAPSE_STRUCUTRE_WEIGHT_STATE_ACCUMULATOR_IMPL_H_ + +//--------------------------------------- +// Structures +//--------------------------------------- +//! Plastic synapse contains normal 16-bit weight and an accumulator +typedef struct plastic_synapse_t { + //! The state + weight_t weight; + //! The accumulator + int16_t accumulator; +} plastic_synapse_t; + +//! The update state is a weight state with 32-bit ARM-friendly version of the +//! accumulator +typedef struct update_state_t { + //! The weight staet + weight_state_t weight_state; + //! The accumulator (in ARM-friendly format) + int32_t accumulator; +} update_state_t; + +//! Final states are actually directly what is stored +typedef plastic_synapse_t final_state_t; + +#include "synapse_structure.h" + +//! \brief Get the update state from the synapse structure +//! \param[in] synaptic_word: The plastic synapse data +//! \param[in] synapse_type: What (supported) type of synapse is this? +//! \return The update state +//! \details +//! Creates the update state, using weight-dependence to initialise the +//! weight state, and copying other parameters from the synaptic word into +//! 32-bit form. +static inline update_state_t synapse_structure_get_update_state( + plastic_synapse_t synaptic_word, index_t synapse_type) { + update_state_t update_state; + update_state.weight_state = + weight_get_initial(synaptic_word.weight, synapse_type); + update_state.accumulator = (int32_t) synaptic_word.accumulator; + return update_state; +} + +//--------------------------------------- +//! \brief Get the final state from the update state. +//! \param[in] state: the update state +//! \return the final state +static inline final_state_t synapse_structure_get_final_state( + update_state_t state) { + // Get weight from state + weight_t weight = weight_get_final(state.weight_state); + + // Build this into synaptic word along with updated accumulator and state + return (final_state_t) { + .weight = weight, + .accumulator = (int16_t) state.accumulator + }; +} + +//--------------------------------------- +//! \brief Get the final weight from the final state +//! \param[in] final_state: the final state +//! \return the final weight +static inline weight_t synapse_structure_get_final_weight( + final_state_t final_state) { + return final_state.weight; +} + +//--------------------------------------- +//! \brief Get the final plastic synapse data from the final state +//! \param[in] final_state: the final state +//! \return the final plastic synapse data, ready to be stored +static inline plastic_synapse_t synapse_structure_get_final_synaptic_word( + final_state_t final_state) { + return final_state; +} + +//--------------------------------------- +//! \brief Create the initial plastic synapse data +//! \param[in] weight: the initial synaptic weight +//! \return the plastic synapse data +static inline plastic_synapse_t synapse_structure_create_synapse( + weight_t weight) { + return (plastic_synapse_t) { + .weight = weight, + .accumulator = 0 + }; +} + +//--------------------------------------- +//! \brief Get the current synaptic weight from the plastic synapse data +//! \param[in] synaptic_word: the plastic synapse data +//! \return the current synaptic weight +static inline weight_t synapse_structure_get_weight( + plastic_synapse_t synaptic_word) { + return synaptic_word.weight; +} + +#endif // _SYNAPSE_STRUCUTRE_WEIGHT_STATE_ACCUMULATOR_IMPL_H_ diff --git a/neural_modelling/src/meanfield/plasticity/stdp/synapse_structure/synapse_structure_weight_impl.h b/neural_modelling/src/meanfield/plasticity/stdp/synapse_structure/synapse_structure_weight_impl.h new file mode 100644 index 00000000000..cc2bd3f0be5 --- /dev/null +++ b/neural_modelling/src/meanfield/plasticity/stdp/synapse_structure/synapse_structure_weight_impl.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Synapses just hold weight +#ifndef _SYNAPSE_STRUCUTRE_WEIGHT_IMPL_H_ +#define _SYNAPSE_STRUCUTRE_WEIGHT_IMPL_H_ + +//--------------------------------------- +// Structures +//--------------------------------------- +//! Plastic synapse types are just weights; +typedef weight_t plastic_synapse_t; + +//! The update state is purely a weight state +typedef weight_state_t update_state_t; + +// The final state is just a weight as this is +//! Both the weight and the synaptic word +typedef weight_t final_state_t; + +//--------------------------------------- +// Synapse interface functions +//--------------------------------------- +//! \brief Get the update state from the synapse structure +//! \param[in] synaptic_word: The plastic synapse data +//! \param[in] synapse_type: What (supported) type of synapse is this? +//! \return The update state +static inline update_state_t synapse_structure_get_update_state( + plastic_synapse_t synaptic_word, index_t synapse_type) { + return weight_get_initial(synaptic_word, synapse_type); +} + +//--------------------------------------- +//! \brief Get the final state from the update state. +//! \param[in] state: the update state +//! \return the final state +static inline final_state_t synapse_structure_get_final_state( + update_state_t state) { + return weight_get_final(state); +} + +//--------------------------------------- +//! \brief Get the final weight from the final state +//! \param[in] final_state: the final state +//! \return the final weight +static inline weight_t synapse_structure_get_final_weight( + final_state_t final_state) { + return final_state; +} + +//--------------------------------------- +//! \brief Get the final plastic synapse data from the final state +//! \param[in] final_state: the final state +//! \return the final plastic synapse data, ready to be stored +static inline plastic_synapse_t synapse_structure_get_final_synaptic_word( + final_state_t final_state) { + return final_state; +} + +//--------------------------------------- +//! \brief Create the initial plastic synapse data +//! \param[in] weight: the initial synaptic weight +//! \return the plastic synapse data +static inline plastic_synapse_t synapse_structure_create_synapse( + weight_t weight) { + return weight; +} + +//--------------------------------------- +//! \brief Get the current synaptic weight from the plastic synapse data +//! \param[in] synaptic_word: the plastic synapse data +//! \return the current synaptic weight +static inline weight_t synapse_structure_get_weight( + plastic_synapse_t synaptic_word) { + return synaptic_word; +} + +#endif // _SYNAPSE_STRUCUTRE_WEIGHT_IMPL_H_ diff --git a/neural_modelling/src/meanfield/plasticity/stdp/synapse_structure/synapse_structure_weight_state_accumulator_impl.h b/neural_modelling/src/meanfield/plasticity/stdp/synapse_structure/synapse_structure_weight_state_accumulator_impl.h new file mode 100644 index 00000000000..09c3bfd0bc6 --- /dev/null +++ b/neural_modelling/src/meanfield/plasticity/stdp/synapse_structure/synapse_structure_weight_state_accumulator_impl.h @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Synapse made of weight, accumulator, and other state +#ifndef _SYNAPSE_STRUCUTRE_WEIGHT_STATE_ACCUMULATOR_IMPL_H_ +#define _SYNAPSE_STRUCUTRE_WEIGHT_STATE_ACCUMULATOR_IMPL_H_ + +//--------------------------------------- +// Structures +//--------------------------------------- +//! Plastic synapse contains normal 16-bit weight, a small state machine and an +//! accumulator +typedef struct plastic_synapse_t { + weight_t weight; //!< Weight + int8_t accumulator; //!< Accumulator + uint8_t state; //!< State machine state +} plastic_synapse_t; + +//! The update state is a weight state with 32-bit ARM-friendly versions of the +//! accumulator and the state +typedef struct update_state_t { + weight_state_t weight_state; //!< Weight state + int32_t accumulator; //!< Accumulator + int32_t state; //!< State machine state +} update_state_t; + +//! Final states are actually directly what is stored +typedef plastic_synapse_t final_state_t; + +#include "synapse_structure.h" + +//! \brief Get the update state from the synapse structure +//! \param[in] synaptic_word: The plastic synapse data +//! \param[in] synapse_type: What (supported) type of synapse is this? +//! \return The update state +//! \details +//! Creates update state, using weight dependence to initialise the weight +//! state, and copying other parameters from the synaptic word into 32-bit +//! form +static inline update_state_t synapse_structure_get_update_state( + plastic_synapse_t synaptic_word, index_t synapse_type) { + update_state_t update_state = { + .weight_state = weight_get_initial(synaptic_word.weight, synapse_type), + .accumulator = (int32_t) synaptic_word.accumulator, + .state = (uint32_t) synaptic_word.state + }; + return update_state; +} + +//--------------------------------------- +//! \brief Get the final state from the update state. +//! \param[in] state: the update state +//! \return the final state +static inline final_state_t synapse_structure_get_final_state( + update_state_t state) { + // Get weight from state + weight_t weight = weight_get_final(state.weight_state); + + // Build this into synaptic word along with updated accumulator and state + return (final_state_t) { + .weight = weight, + .accumulator = (int8_t) state.accumulator, + .state = (uint8_t) state.state + }; +} + +//--------------------------------------- +//! \brief Get the final weight from the final state +//! \param[in] final_state: the final state +//! \return the final weight +static inline weight_t synapse_structure_get_final_weight( + final_state_t final_state) { + return final_state.weight; +} + +//--------------------------------------- +//! \brief Get the final plastic synapse data from the final state +//! \param[in] final_state: the final state +//! \return the final plastic synapse data, ready to be stored +static inline plastic_synapse_t synapse_structure_get_final_synaptic_word( + final_state_t final_state) { + return final_state; +} + +//--------------------------------------- +//! \brief Create the initial plastic synapse data +//! \param[in] weight: the initial synaptic weight +//! \return the plastic synapse data +static inline plastic_synapse_t synapse_structure_create_synapse( + weight_t weight) { + plastic_synapse_t initial = { + .weight = weight, + .accumulator = 0, + .state = 0 + }; + return initial; +} + +//--------------------------------------- +//! \brief Get the current synaptic weight from the plastic synapse data +//! \param[in] synaptic_word: the plastic synapse data +//! \return the current synaptic weight +static inline weight_t synapse_structure_get_weight( + plastic_synapse_t synaptic_word) { + return synaptic_word.weight; +} + +#endif _SYNAPSE_STRUCUTRE_WEIGHT_STATE_ACCUMULATOR_IMPL_H_ diff --git a/neural_modelling/src/meanfield/plasticity/stdp/synapse_structure/synapse_structure_weight_state_accumulator_window_impl.h b/neural_modelling/src/meanfield/plasticity/stdp/synapse_structure/synapse_structure_weight_state_accumulator_window_impl.h new file mode 100644 index 00000000000..d17d8374b70 --- /dev/null +++ b/neural_modelling/src/meanfield/plasticity/stdp/synapse_structure/synapse_structure_weight_state_accumulator_window_impl.h @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Synapses made of weight, accumulator, other state, and window +#ifndef _SYNAPSE_STRUCTURE_WEIGHT_STATE_ACCUMULATOR_WINDOW_H_ +#define _SYNAPSE_STRUCTURE_WEIGHT_STATE_ACCUMULATOR_WINDOW_H_ + +//! \brief Plastic synapse contains normal 16-bit weight, a small state machine, +//! an accumulator, and the size of the relevance window +typedef struct plastic_synapse_t { + unsigned int weight : 16; //!< The weight + int accumulator : 4; //!< The accumulator + unsigned int state : 2; //!< The state machine state + unsigned int window_length : 10; //!< The window length +} plastic_synapse_t; + +//! The update state is a weight state with 32-bit ARM-friendly versions of the +//! accumulator, state and window length +typedef struct update_state_t { + weight_state_t weight_state; //!< The weight state + + int32_t accumulator; //!< The accumulator + int32_t state; //!< The state machine state + + uint32_t window_length; //!< The window length +} update_state_t; + +//! Final states are actually directly what is stored +typedef plastic_synapse_t final_state_t; + +#include "synapse_structure.h" + +//! \brief Get the update state from the synapse structure +//! \param[in] synaptic_word: The plastic synapse data +//! \param[in] synapse_type: What (supported) type of synapse is this? +//! \return The update state +static inline update_state_t synapse_structure_get_update_state( + plastic_synapse_t synaptic_word, index_t synapse_type) { + // Create update state, using weight dependance to initialise the weight + // state and copying other parameters from the synaptic word into 32-bit + // form + update_state_t update_state; + update_state.weight_state = + weight_get_initial(synaptic_word.weight, synapse_type); + update_state.accumulator = (int32_t) synaptic_word.accumulator; + update_state.state = (uint32_t) synaptic_word.state; + update_state.window_length = (uint32_t) synaptic_word.window_length; + return update_state; +} + +//--------------------------------------- +//! \brief Get the final state from the update state. +//! \param[in] state: the update state +//! \return the final state +static inline final_state_t synapse_structure_get_final_state( + update_state_t state) { + // Get weight from state + weight_t weight = weight_get_final(state.weight_state); + + // Build this into synaptic word along with updated accumulator and state + return (final_state_t) { + .weight = weight, + .accumulator = (int) state.accumulator, + .state = (unsigned int) state.state, + .window_length = (unsigned int)state.window_length + }; +} + +//--------------------------------------- +//! \brief Get the final weight from the final state +//! \param[in] final_state: the final state +//! \return the final weight +static inline weight_t synapse_structure_get_final_weight( + final_state_t final_state) { + return final_state.weight; +} + +//--------------------------------------- +//! \brief Get the final plastic synapse data from the final state +//! \param[in] final_state: the final state +//! \return the final plastic synapse data, ready to be stored +static inline plastic_synapse_t synapse_structure_get_final_synaptic_word( + final_state_t final_state) { + return final_state; +} + +//--------------------------------------- +//! \brief Create the initial plastic synapse data +//! \param[in] weight: the initial synaptic weight +//! \return the plastic synapse data +static inline plastic_synapse_t synapse_structure_create_synapse( + weight_t weight) { + return (plastic_synapse_t) { + .weight = weight, + .accumulator = 0, + .state = 0, + .window_length = 0 + }; +} + +//--------------------------------------- +//! \brief Get the current synaptic weight from the plastic synapse data +//! \param[in] synaptic_word: the plastic synapse data +//! \return the current synaptic weight +static inline weight_t synapse_structure_get_weight( + plastic_synapse_t synaptic_word) { + return synaptic_word.weight; +} + +#endif // _SYNAPSE_STRUCTURE_WEIGHT_STATE_ACCUMULATOR_WINDOW_H_ diff --git a/neural_modelling/src/meanfield/plasticity/stdp/timing_dependence/my_timing_impl.c b/neural_modelling/src/meanfield/plasticity/stdp/timing_dependence/my_timing_impl.c new file mode 100644 index 00000000000..43e26628967 --- /dev/null +++ b/neural_modelling/src/meanfield/plasticity/stdp/timing_dependence/my_timing_impl.c @@ -0,0 +1,32 @@ +#include "my_timing_impl.h" + +// TODO: Describe the layout of the configuration *in SDRAM* +typedef struct my_timing_config { + accum my_potentiation_parameter; + accum my_depression_parameter; +} my_timing_config_t; + +// TODO: Set up any variables here +accum my_potentiation_parameter; +accum my_depression_parameter; + +//--------------------------------------- +// Functions +//--------------------------------------- +address_t timing_initialise(address_t address) { + + log_info("timing_initialise: starting"); + log_info("\tSTDP my timing rule"); + + // TODO: copy parameters from memory + my_timing_config_t *config = (my_timing_config_t *) address; + my_potentiation_parameter = config->my_potentiation_parameter; + my_depression_parameter = config->my_depression_parameter; + + log_info("my potentiation parameter = %k", my_potentiation_parameter); + log_info("my depression parameter = %k", my_depression_parameter); + log_info("timing_initialise: completed successfully"); + + // Return the address after the configuration (word aligned) + return (address_t) (config + 1); +} diff --git a/neural_modelling/src/meanfield/plasticity/stdp/timing_dependence/my_timing_impl.h b/neural_modelling/src/meanfield/plasticity/stdp/timing_dependence/my_timing_impl.h new file mode 100644 index 00000000000..639af0d1a77 --- /dev/null +++ b/neural_modelling/src/meanfield/plasticity/stdp/timing_dependence/my_timing_impl.h @@ -0,0 +1,128 @@ +#ifndef _MY_TIMING_H_ +#define _MY_TIMING_H_ + +// These need to be defined before including any synapse stuff +#define SYNAPSE_TYPE_BITS 1 +#define SYNAPSE_TYPE_COUNT 2 + +// TODO: Add any variables to be stored in the post trace structure +typedef struct post_trace_t { +} post_trace_t; + +// TODO: Add any variables to be stored in the pre trace structure +typedef struct pre_trace_t { +} pre_trace_t; + +// Because spin1_memcpy() is used in various places +#include + +// Include generic plasticity maths functions +#include + +// TODO: Ensure the correct number of weight terms is chosen +#include + +// TODO: Choose the required synapse structure +#include + +#include + +// Include debug header for log_info etc +#include + +// Note the parameters will be external +extern accum my_potentiation_parameter; +extern accum my_depression_parameter; + +//--------------------------------------- +// Timing dependence inline functions +//--------------------------------------- +static inline post_trace_t timing_get_initial_post_trace(void) { + + // TODO: Return the values required + return (post_trace_t) {}; +} + +//--------------------------------------- +static inline post_trace_t timing_add_post_spike( + uint32_t time, uint32_t last_time, post_trace_t last_trace) { + use(&last_time); + use(&last_trace); + + log_debug("\tdelta_time=%u\n", time - last_time); + + // TODO: Perform operations when a new post-spike occurs + + // Return new pre- synaptic event with decayed trace values with energy + // for new spike added + return (post_trace_t) {}; +} + +//--------------------------------------- +static inline pre_trace_t timing_add_pre_spike( + uint32_t time, uint32_t last_time, pre_trace_t last_trace) { + use(&last_time); + use(&last_trace); + + log_debug("\tdelta_time=%u\n", time - last_time); + + // TODO: Perform operations when a new pre-spike occurs + + return (pre_trace_t ) {}; +} + +//--------------------------------------- +static inline update_state_t timing_apply_pre_spike( + uint32_t time, pre_trace_t trace, uint32_t last_pre_time, + pre_trace_t last_pre_trace, uint32_t last_post_time, + post_trace_t last_post_trace, update_state_t previous_state) { + use(&trace); + use(&last_pre_time); + use(&last_pre_trace); + use(&last_post_trace); + + // TODO: Perform depression on pre spikes that occur after the + // current spike + accum time_since_last_post = (accum) (time - last_post_time); + if (time_since_last_post > 0) { + int32_t decayed_o1 = (int32_t) + (time_since_last_post * my_depression_parameter); + + log_debug("\t\t\ttime_since_last_post=%k, decayed_o1=%d\n", + time_since_last_post, decayed_o1); + + // Apply depression to state (which is a weight_state) + return weight_one_term_apply_depression(previous_state, decayed_o1); + } else { + return previous_state; + } +} + +//--------------------------------------- +static inline update_state_t timing_apply_post_spike( + uint32_t time, post_trace_t trace, uint32_t last_pre_time, + pre_trace_t last_pre_trace, uint32_t last_post_time, + post_trace_t last_post_trace, update_state_t previous_state) { + use(&trace); + use(&last_pre_trace); + use(&last_post_time); + use(&last_post_trace); + + // TODO: Perform potentiation on post spikes that occur after the + // current spike + accum time_since_last_pre = (accum) (time - last_pre_time); + if (time_since_last_pre > 0) { + int32_t decayed_r1 = (int32_t) + (time_since_last_pre * my_potentiation_parameter); + + log_debug("\t\t\ttime_since_last_pre=%k, decayed_r1=%d\n", + time_since_last_pre, decayed_r1); + + // Apply potentiation to state (which is a weight_state) + return weight_one_term_apply_potentiation(previous_state, decayed_r1); + } else { + return previous_state; + } +} + +#endif // _MY_TIMING_H_ diff --git a/neural_modelling/src/meanfield/plasticity/stdp/timing_dependence/timing.h b/neural_modelling/src/meanfield/plasticity/stdp/timing_dependence/timing.h new file mode 100644 index 00000000000..e04e472c56f --- /dev/null +++ b/neural_modelling/src/meanfield/plasticity/stdp/timing_dependence/timing.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \dir +//! \brief STDP timing dependence rules +//! \file +//! \brief API for timing rules +#ifndef _TIMING_H_ +#define _TIMING_H_ + +#include + +//! \brief Initialise the timing dependence state (global) from SDRAM +//! \param[in] address: Location in SDRAM of timing data +//! \return address of first word after the timing data +address_t timing_initialise(address_t address); + +//! \brief Get an initial post-synaptic timing trace +//! \return the post trace +static post_trace_t timing_get_initial_post_trace(void); + +//! \brief Add a post spike to the post trace +//! \param[in] time: the time of the spike +//! \param[in] last_time: the time of the previous spike update +//! \param[in] last_trace: the post trace to update +//! \return the updated post trace +static post_trace_t timing_add_post_spike( + uint32_t time, uint32_t last_time, post_trace_t last_trace); + +//! \brief Add a pre spike to the pre trace +//! \param[in] time: the time of the spike +//! \param[in] last_time: the time of the previous spike update +//! \param[in] last_trace: the pre trace to update +//! \return the updated pre trace +static pre_trace_t timing_add_pre_spike( + uint32_t time, uint32_t last_time, pre_trace_t last_trace); + +//! \brief Apply a pre-spike timing rule state update +//! \param[in] time: the current time +//! \param[in] trace: the current pre-spike trace +//! \param[in] last_pre_time: the time of the last pre-spike +//! \param[in] last_pre_trace: the trace of the last pre-spike +//! \param[in] last_post_time: the time of the last post-spike +//! \param[in] last_post_trace: the trace of the last post-spike +//! \param[in] previous_state: the state to update +//! \return the updated state +static update_state_t timing_apply_pre_spike( + uint32_t time, pre_trace_t trace, uint32_t last_pre_time, + pre_trace_t last_pre_trace, uint32_t last_post_time, + post_trace_t last_post_trace, update_state_t previous_state); + +//! \brief Apply a post-spike timing rule state update +//! \param[in] time: the current time +//! \param[in] trace: the current post-spike trace +//! \param[in] last_pre_time: the time of the last pre-spike +//! \param[in] last_pre_trace: the trace of the last pre-spike +//! \param[in] last_post_time: the time of the last post-spike +//! \param[in] last_post_trace: the trace of the last post-spike +//! \param[in] previous_state: the state to update +//! \return the updated state +static update_state_t timing_apply_post_spike( + uint32_t time, post_trace_t trace, uint32_t last_pre_time, + pre_trace_t last_pre_trace, uint32_t last_post_time, + post_trace_t last_post_trace, update_state_t previous_state); + +#endif // _TIMING_H_ diff --git a/neural_modelling/src/meanfield/plasticity/stdp/timing_dependence/timing_nearest_pair_impl.h b/neural_modelling/src/meanfield/plasticity/stdp/timing_dependence/timing_nearest_pair_impl.h new file mode 100644 index 00000000000..1ce07027cc1 --- /dev/null +++ b/neural_modelling/src/meanfield/plasticity/stdp/timing_dependence/timing_nearest_pair_impl.h @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Timing rule using msot recent spike pair +#ifndef _TIMING_NEAREST_PAIR_IMPL_H_ +#define _TIMING_NEAREST_PAIR_IMPL_H_ + +//--------------------------------------- +// Structures +//--------------------------------------- +typedef struct post_trace_t { +} post_trace_t; + +typedef struct pre_trace_t { +} pre_trace_t; + +#include +#include "timing.h" +#include + +// Include debug header for log_info etc +#include + +// Include generic plasticity maths functions +#include + +//--------------------------------------- +// Timing dependence inline functions +//--------------------------------------- +//! \brief Get an initial post-synaptic timing trace +//! \return the post trace +static inline post_trace_t timing_get_initial_post_trace(void) { + return (post_trace_t) {}; +} + +//--------------------------------------- +//! \brief Add a post spike to the post trace +//! \param[in] time: the time of the spike +//! \param[in] last_time: the time of the previous spike update +//! \param[in] last_trace: the post trace to update +//! \return the updated post trace +static inline post_trace_t timing_add_post_spike( + uint32_t time, uint32_t last_time, UNUSED post_trace_t last_trace) { + log_debug("\tdelta_time=%u\n", time - last_time); + + // Return new pre- synaptic event with decayed trace values with energy + // for new spike added + return (post_trace_t) {}; +} + +//--------------------------------------- +//! \brief Add a pre spike to the pre trace +//! \param[in] time: the time of the spike +//! \param[in] last_time: the time of the previous spike update +//! \param[in] last_trace: the pre trace to update +//! \return the updated pre trace +static inline pre_trace_t timing_add_pre_spike( + uint32_t time, uint32_t last_time, UNUSED pre_trace_t last_trace) { + log_debug("\tdelta_time=%u\n", time - last_time); + + return (pre_trace_t ) {}; +} + +//--------------------------------------- +//! \brief Apply a pre-spike timing rule state update +//! \param[in] time: the current time +//! \param[in] trace: the current pre-spike trace +//! \param[in] last_pre_time: the time of the last pre-spike +//! \param[in] last_pre_trace: the trace of the last pre-spike +//! \param[in] last_post_time: the time of the last post-spike +//! \param[in] last_post_trace: the trace of the last post-spike +//! \param[in] previous_state: the state to update +//! \return the updated state +static inline update_state_t timing_apply_pre_spike( + uint32_t time, UNUSED pre_trace_t trace, UNUSED uint32_t last_pre_time, + UNUSED pre_trace_t last_pre_trace, uint32_t last_post_time, + UNUSED post_trace_t last_post_trace, update_state_t previous_state) { + extern int16_lut *tau_minus_lookup; + + // Get time of event relative to last post-synaptic event + uint32_t time_since_last_post = time - last_post_time; + int32_t decayed_o1 = maths_lut_exponential_decay( + time_since_last_post, tau_minus_lookup); + + log_debug("\t\t\ttime_since_last_post=%u, decayed_o1=%d\n", + time_since_last_post, decayed_o1); + + // Apply depression to state (which is a weight_state) + return weight_one_term_apply_depression(previous_state, decayed_o1); +} + +//--------------------------------------- +//! \brief Apply a post-spike timing rule state update +//! \param[in] time: the current time +//! \param[in] trace: the current post-spike trace +//! \param[in] last_pre_time: the time of the last pre-spike +//! \param[in] last_pre_trace: the trace of the last pre-spike +//! \param[in] last_post_time: the time of the last post-spike +//! \param[in] last_post_trace: the trace of the last post-spike +//! \param[in] previous_state: the state to update +//! \return the updated state +static inline update_state_t timing_apply_post_spike( + uint32_t time, UNUSED post_trace_t trace, uint32_t last_pre_time, + UNUSED pre_trace_t last_pre_trace, uint32_t last_post_time, + UNUSED post_trace_t last_post_trace, update_state_t previous_state) { + extern int16_lut *tau_plus_lookup; + + // Get time of event relative to last pre-synaptic event + uint32_t time_since_last_pre = time - last_pre_time; + uint32_t time_since_last_post = time - last_post_time; + + if (time_since_last_pre > 0) { + int32_t decayed_r1 = maths_lut_exponential_decay( + time_since_last_pre, tau_plus_lookup); + + log_debug("\t\t\ttime_since_last_pret=%u, decayed_r1=%d\n", + time_since_last_pre, decayed_r1); + log_debug("\t\t\ttime_since_last_post=%u, decayed_r1=%d\n", + time_since_last_post, decayed_r1); + + if (time_since_last_post < time_since_last_pre) { + log_debug("\t\t\tSetting trace to zero as not first pre-post pairing"); + decayed_r1 = 0; + } + + // Apply potentiation to state (which is a weight_state) + return weight_one_term_apply_potentiation(previous_state, decayed_r1); + } else { + return previous_state; + } +} + +#endif // _TIMING_NEAREST_PAIR_IMPL_H_ diff --git a/neural_modelling/src/meanfield/plasticity/stdp/weight_dependence/my_weight_impl.c b/neural_modelling/src/meanfield/plasticity/stdp/weight_dependence/my_weight_impl.c new file mode 100644 index 00000000000..dfe6eb4293e --- /dev/null +++ b/neural_modelling/src/meanfield/plasticity/stdp/weight_dependence/my_weight_impl.c @@ -0,0 +1,36 @@ +#include "my_weight_impl.h" + +// Global plasticity parameter data +plasticity_weight_region_data_t *plasticity_weight_region_data; + +address_t weight_initialise( + address_t address, uint32_t n_synapse_types, + uint32_t *ring_buffer_to_input_buffer_left_shifts) { + + // This can be used to indicate the scaling used on the weights + use(ring_buffer_to_input_buffer_left_shifts); + + log_info("weight_initialise: starting"); + log_info("\tSTDP my weight dependence"); + + // Copy plasticity parameter data from address; same format in both + plasticity_weight_region_data = (plasticity_weight_region_data_t *) + spin1_malloc(n_synapse_types * sizeof(plasticity_weight_region_data_t)); + if (plasticity_weight_region_data == NULL) { + log_error("Error allocating plasticity weight data"); + return NULL; + } + plasticity_weight_region_data_t *config = + (plasticity_weight_region_data_t *) address; + for (uint32_t s = 0; s < n_synapse_types; s++) { + plasticity_weight_region_data[s].min_weight = config[s].min_weight; + plasticity_weight_region_data[s].max_weight = config[s].max_weight; + plasticity_weight_region_data[s].my_parameter = config[s].my_parameter; + + // TODO: Copy any other data + } + log_info("weight_initialise: completed successfully"); + + // Return end address of region + return (address_t) &config[n_synapse_types]; +} diff --git a/neural_modelling/src/meanfield/plasticity/stdp/weight_dependence/my_weight_impl.h b/neural_modelling/src/meanfield/plasticity/stdp/weight_dependence/my_weight_impl.h new file mode 100644 index 00000000000..c46470b94dc --- /dev/null +++ b/neural_modelling/src/meanfield/plasticity/stdp/weight_dependence/my_weight_impl.h @@ -0,0 +1,108 @@ +#ifndef _MY_WEIGHT_H_ +#define _MY_WEIGHT_H_ + +// Because spin1_memcpy() is used in various places +#include + +// Include generic plasticity maths functions +#include +#include +#include + +#include + +// A structure for the variables +typedef struct { + int32_t min_weight; + int32_t max_weight; + + int32_t my_parameter; + + // TODO: Put in all required parameters + +} plasticity_weight_region_data_t; + +// An intermediate data structure; can have more accuracy and use more storage +// than the variable structure e.g. weight might be 16-bit but stored as 32-bit +// here +typedef struct { + int32_t initial_weight; + + int32_t potentiation; + int32_t depression; + + const plasticity_weight_region_data_t *weight_region; + + // TODO: Put in any variables required in the intermediate state +} weight_state_t; + +// TODO: Ensure this includes and implements the correct interface +#include + +// The external variables of the weight rule +extern plasticity_weight_region_data_t *plasticity_weight_region_data; + +//--------------------------------------- +// STDP weight dependence functions +//--------------------------------------- +static inline weight_state_t weight_get_initial( + weight_t weight, index_t synapse_type) { + + // TODO: Store the data in the intermediate data structure + return (weight_state_t ) { + .initial_weight = (int32_t) weight, + .potentiation = 0, + .depression = 0, + .weight_region = &plasticity_weight_region_data[synapse_type] + }; +} + +//--------------------------------------- +static inline weight_state_t weight_one_term_apply_depression( + weight_state_t state, int32_t depression) { + + // TODO: Perform intermediate operations in relation to depression + // Note: Can save up to perform complex operations until the end + state.depression += depression; + return state; +} + +//--------------------------------------- +static inline weight_state_t weight_one_term_apply_potentiation( + weight_state_t state, int32_t potentiation) { + + // TODO: Perform intermediate operations in relation to potentiation + // Note: Can save up to perform complex operations until the end + state.potentiation += potentiation; + return state; +} + +//--------------------------------------- +static inline weight_t weight_get_final(weight_state_t new_state) { + + // TODO: Perform operations to get the final weight from the intermediate + // state, taking into account all potentiation and depression + // Note: it is recommended to do a single complex operation here rather + // than one for each potentiation or depression if possible + + int32_t potentiation = + new_state.potentiation * new_state.weight_region->my_parameter; + int32_t depression = + new_state.depression * new_state.weight_region->my_parameter; + + int32_t new_weight = new_state.initial_weight + potentiation - depression; + + // Clamp new weight + new_weight = MIN( + new_state.weight_region->max_weight, + MAX(new_weight, new_state.weight_region->min_weight)); + + log_debug("old_weight:%u, potentiation:%d, depression:%d, " + "scaled potentiation:%d, scaled depression:%d, new_weight:%d", + new_state.initial_weight, new_state.potentiation, + new_state.depression, potentiation, depression, new_weight); + + return (weight_t) new_weight; +} + +#endif // _MY_WEIGHT_H_ diff --git a/neural_modelling/src/meanfield/plasticity/stdp/weight_dependence/weight.h b/neural_modelling/src/meanfield/plasticity/stdp/weight_dependence/weight.h new file mode 100644 index 00000000000..d8cb54d2b29 --- /dev/null +++ b/neural_modelling/src/meanfield/plasticity/stdp/weight_dependence/weight.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/*! + * \dir + * \brief STDP weight dependence rules + * \file + * \brief interface for different weight implementations for the weight half of + * a STDP rule. + * + * \details the API interface contains: + * - weight_initialise(): + * Initialises the weight aspect of a STDP rule. + * - weight_get_initial(): + * Converts the stored weight into an update-able form. + * - weight_get_final(): + * Converts the updated weight into store-able form. + */ + +#ifndef _WEIGHT_H_ +#define _WEIGHT_H_ + +#include +#include + +/*! + * \brief Initialises the weight aspect of an STDP rule. + * \param[in] address: the absolute address in SRAM where the weight parameters + * are stored. + * \param[in] n_synapse_types: The number of synapse types + * \param[in] ring_buffer_to_input_buffer_left_shifts: how much a value needs + * to be shifted in the left direction to support comprises with fixed + * point arithmetic + * \return the end of the weight region as an absolute SDRAM memory address. + */ +address_t weight_initialise( + address_t address, uint32_t n_synapse_types, + uint32_t *ring_buffer_to_input_buffer_left_shifts); + +/*! + * \brief Gets the initial weight state. + * \param[in] weight: The weight at the start + * \param[in] synapse_type: The type of synapse involved + * \return The initial weight state. + */ +static weight_state_t weight_get_initial(weight_t weight, index_t synapse_type); + +/*! + * \brief Gets the final weight. + * \param[in] new_state: The updated weight state + * \return The new weight. + */ +static weight_t weight_get_final(weight_state_t new_state); + +#endif // _WEIGHT_H_ diff --git a/neural_modelling/src/meanfield/plasticity/stdp/weight_dependence/weight_additive_one_term_impl.c b/neural_modelling/src/meanfield/plasticity/stdp/weight_dependence/weight_additive_one_term_impl.c new file mode 100644 index 00000000000..f0dbf524f1e --- /dev/null +++ b/neural_modelling/src/meanfield/plasticity/stdp/weight_dependence/weight_additive_one_term_impl.c @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Support code for weight_additive_one_term_impl.h +#include "weight_additive_one_term_impl.h" + +//--------------------------------------- +// Globals +//--------------------------------------- +//! Global plasticity parameter data +plasticity_weight_region_data_t *plasticity_weight_region_data; + +//! \brief How the configuration data for additive_one_term is laid out in +//! SDRAM. The layout is an array of these. +typedef struct { + int32_t min_weight; + int32_t max_weight; + int32_t a2_plus; + int32_t a2_minus; +} additive_one_term_config_t; + +//--------------------------------------- +// Functions +//--------------------------------------- +address_t weight_initialise( + address_t address, uint32_t n_synapse_types, + UNUSED uint32_t *ring_buffer_to_input_buffer_left_shifts) { + log_debug("weight_initialise: starting"); + log_debug("\tSTDP additive one-term weight dependence"); + + // Copy plasticity region data from address + // **NOTE** this seems somewhat safer than relying on sizeof + additive_one_term_config_t *config = (additive_one_term_config_t *) address; + + plasticity_weight_region_data_t *dtcm_copy = plasticity_weight_region_data = + spin1_malloc(sizeof(plasticity_weight_region_data_t) * n_synapse_types); + if (dtcm_copy == NULL) { + log_error("Could not initialise weight region data"); + return NULL; + } + for (uint32_t s = 0; s < n_synapse_types; s++, config++) { + dtcm_copy[s].min_weight = config->min_weight; + dtcm_copy[s].max_weight = config->max_weight; + dtcm_copy[s].a2_plus = config->a2_plus; + dtcm_copy[s].a2_minus = config->a2_minus; + + log_debug("\tSynapse type %u: Min weight:%d, Max weight:%d, A2+:%d, A2-:%d", + s, dtcm_copy[s].min_weight, dtcm_copy[s].max_weight, + dtcm_copy[s].a2_plus, dtcm_copy[s].a2_minus); + } + log_debug("weight_initialise: completed successfully"); + + // Return end address of region + return (address_t) config; +} diff --git a/neural_modelling/src/meanfield/plasticity/stdp/weight_dependence/weight_additive_one_term_impl.h b/neural_modelling/src/meanfield/plasticity/stdp/weight_dependence/weight_additive_one_term_impl.h new file mode 100644 index 00000000000..1de7a96221d --- /dev/null +++ b/neural_modelling/src/meanfield/plasticity/stdp/weight_dependence/weight_additive_one_term_impl.h @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Additive single-term weight dependence rule +#ifndef _WEIGHT_ADDITIVE_ONE_TERM_IMPL_H_ +#define _WEIGHT_ADDITIVE_ONE_TERM_IMPL_H_ + +// Include generic plasticity maths functions +#include +#include +#include + +#include + +//--------------------------------------- +// Structures +//--------------------------------------- +//! The configuration of the rule +typedef struct { + int32_t min_weight; //!< Minimum weight + int32_t max_weight; //!< Maximum weight + + int32_t a2_plus; //!< Scaling factor for weight delta on potentiation + int32_t a2_minus; //!< Scaling factor for weight delta on depression +} plasticity_weight_region_data_t; + +//! The current state data for the rule +typedef struct { + int32_t initial_weight; //!< The starting weight + + int32_t a2_plus; //!< Cumulative potentiation delta + int32_t a2_minus; //!< Cumulative depression delta + + //! Reference to the configuration data + const plasticity_weight_region_data_t *weight_region; +} weight_state_t; + +#include "weight_one_term.h" + +//--------------------------------------- +// STDP weight dependence functions +//--------------------------------------- +/*! + * \brief Gets the initial weight state. + * \param[in] weight: The weight at the start + * \param[in] synapse_type: The type of synapse involved + * \return The initial weight state. + */ +static inline weight_state_t weight_get_initial( + weight_t weight, index_t synapse_type) { + extern plasticity_weight_region_data_t *plasticity_weight_region_data; + + return (weight_state_t) { + .initial_weight = (int32_t) weight, + .a2_plus = 0, + .a2_minus = 0, + .weight_region = &plasticity_weight_region_data[synapse_type] + }; +} + +//--------------------------------------- +//! \brief Apply the depression rule to the weight state +//! \param[in] state: The weight state to update +//! \param[in] a2_minus: The amount of depression to apply +//! \return the updated weight state +static inline weight_state_t weight_one_term_apply_depression( + weight_state_t state, int32_t a2_minus) { + state.a2_minus += a2_minus; + return state; +} + +//--------------------------------------- +//! \brief Apply the potentiation rule to the weight state +//! \param[in] state: The weight state to update +//! \param[in] a2_plus: The amount of potentiation to apply +//! \return the updated weight state +static inline weight_state_t weight_one_term_apply_potentiation( + weight_state_t state, int32_t a2_plus) { + state.a2_plus += a2_plus; + return state; +} + +//--------------------------------------- +/*! + * \brief Gets the final weight. + * \param[in] new_state: The updated weight state + * \return The new weight. + */ +static inline weight_t weight_get_final(weight_state_t new_state) { + // Scale potentiation and depression + // **NOTE** A2+ and A2- are pre-scaled into weight format + int32_t scaled_a2_plus = STDP_FIXED_MUL_16X16( + new_state.a2_plus, new_state.weight_region->a2_plus); + int32_t scaled_a2_minus = STDP_FIXED_MUL_16X16( + new_state.a2_minus, new_state.weight_region->a2_minus); + + // Apply all terms to initial weight + int32_t new_weight = + new_state.initial_weight + scaled_a2_plus - scaled_a2_minus; + + // Clamp new weight + new_weight = MIN(new_state.weight_region->max_weight, + MAX(new_weight, new_state.weight_region->min_weight)); + + log_debug("\told_weight:%u, a2+:%d, a2-:%d, scaled a2+:%d, scaled a2-:%d," + " new_weight:%d", + new_state.initial_weight, new_state.a2_plus, new_state.a2_minus, + scaled_a2_plus, scaled_a2_minus, new_weight); + + return (weight_t) new_weight; +} + +#endif // _WEIGHT_ADDITIVE_ONE_TERM_IMPL_H_ diff --git a/neural_modelling/src/meanfield/plasticity/stdp/weight_dependence/weight_one_term.h b/neural_modelling/src/meanfield/plasticity/stdp/weight_dependence/weight_one_term.h new file mode 100644 index 00000000000..b4f369dd657 --- /dev/null +++ b/neural_modelling/src/meanfield/plasticity/stdp/weight_dependence/weight_one_term.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief API for single-term weight dependence rules +#ifndef _WEIGHT_ONE_TERM_H_ +#define _WEIGHT_ONE_TERM_H_ + +#include "weight.h" + +//! \brief Apply the depression rule to the weight state +//! \param[in] state: The weight state to update +//! \param[in] depression: The amount of depression to apply +//! \return the updated weight state +static weight_state_t weight_one_term_apply_depression( + weight_state_t state, int32_t depression); + +//! \brief Apply the potentiation rule to the weight state +//! \param[in] state: The weight state to update +//! \param[in] potentiation: The amount of potentiation to apply +//! \return the updated weight state +static weight_state_t weight_one_term_apply_potentiation( + weight_state_t state, int32_t potentiation); + +#endif // _WEIGHT_ONE_TERM_H_ diff --git a/neural_modelling/src/meanfield/plasticity/synapse_dynamics.h b/neural_modelling/src/meanfield/plasticity/synapse_dynamics.h new file mode 100644 index 00000000000..4e3b9941313 --- /dev/null +++ b/neural_modelling/src/meanfield/plasticity/synapse_dynamics.h @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \dir +//! \brief Dynamic synapses +//! \file +//! \brief API for synapse dynamics +#ifndef _SYNAPSE_DYNAMICS_H_ +#define _SYNAPSE_DYNAMICS_H_ + +#include +#include + +//! \brief Initialise the synapse dynamics +//! \param[in] address: Where the configuration data is +//! \param[in] n_neurons: Number of neurons +//! \param[in] n_synapse_types: Number of synapse types +//! \param[in] ring_buffer_to_input_buffer_left_shifts: +//! How to interpret the values from the ring buffers +//! \return Whether the initialisation succeeded. +bool synapse_dynamics_initialise( + address_t address, uint32_t n_neurons, uint32_t n_synapse_types, + uint32_t *ring_buffer_to_input_buffer_left_shifts); + +//! \brief Process the dynamics of the synapses +//! \param[in,out] plastic_region_data: Where the plastic data is +//! \param[in] fixed_region: Where the fixed data is +//! \param[in,out] ring_buffers: The ring buffers +//! \param[in] time: The current simulation time +//! \return ??? +bool synapse_dynamics_process_plastic_synapses( + synapse_row_plastic_data_t *plastic_region_data, + synapse_row_fixed_part_t *fixed_region, + weight_t *ring_buffers, uint32_t time); + +//! \brief Inform the synapses that the neuron fired +//! \param[in] time: The current simulation time +//! \param[in] neuron_index: Which neuron are we processing +void synapse_dynamics_process_post_synaptic_event( + uint32_t time, index_t neuron_index); + +//! \brief Get the intrinsic bias of the synapses +//! \param[in] time: The current simulation time +//! \param[in] neuron_index: Which neuron are we processing +//! \return The intrinsic bias +input_t synapse_dynamics_get_intrinsic_bias( + uint32_t time, index_t neuron_index); + +//! \brief Print the synapse dynamics +//! \param[in] plastic_region_data: Where the plastic data is +//! \param[in] fixed_region: Where the fixed data is +//! \param[in] ring_buffer_to_input_buffer_left_shifts: +//! How to interpret the values from the ring buffers +void synapse_dynamics_print_plastic_synapses( + synapse_row_plastic_data_t *plastic_region_data, + synapse_row_fixed_part_t *fixed_region, + uint32_t *ring_buffer_to_input_buffer_left_shifts); + +//! \brief Get the counters for plastic pre synaptic events based on (if +//! the model was compiled with SYNAPSE_BENCHMARK parameter) or returns 0 +//! \return counters for plastic pre synaptic events or 0 +uint32_t synapse_dynamics_get_plastic_pre_synaptic_events(void); + +//! \brief Get the number of ring buffer saturation events due to adding +//! plastic weights. +//! \return counter for saturation events or 0 +uint32_t synapse_dynamics_get_plastic_saturation_count(void); + +//----------------------------------------------------------------------------- +// Synaptic rewiring functions +//----------------------------------------------------------------------------- + +//! \brief Search the synaptic row for the the connection with the +//! specified post-synaptic ID +//! \param[in] id: the (core-local) ID of the neuron to search for in the +//! synaptic row +//! \param[in] row: the core-local address of the synaptic row +//! \param[out] weight: address to contain the weight of the connection +//! \param[out] delay: address to contain the delay of the connection +//! \param[out] offset: address to contain the offset of the connection +//! \param[out] synapse_type: the synapse type of the connection +//! \return was the search successful? +bool synapse_dynamics_find_neuron( + uint32_t id, synaptic_row_t row, weight_t *weight, uint16_t *delay, + uint32_t *offset, uint32_t *synapse_type); + +//! \brief Remove the entry at the specified offset in the synaptic row +//! \param[in] offset: the offset in the row at which to remove the entry +//! \param[in] row: the core-local address of the synaptic row +//! \return was the removal successful? +bool synapse_dynamics_remove_neuron(uint32_t offset, synaptic_row_t row); + +//! \brief Add an entry in the synaptic row +//! \param[in] id: the (core-local) ID of the post-synaptic neuron to be added +//! \param[in] row: the core-local address of the synaptic row +//! \param[in] weight: the initial weight associated with the connection +//! \param[in] delay: the delay associated with the connection +//! \param[in] type: the type of the connection (e.g. inhibitory) +//! \return was the addition successful? +bool synapse_dynamics_add_neuron( + uint32_t id, synaptic_row_t row, weight_t weight, + uint32_t delay, uint32_t type); + +//! \brief Get the number of connections in the given row +//! \param[in] fixed: the fixed region of the synaptic row +//! \return The number of connections in the row +uint32_t synapse_dynamics_n_connections_in_row(synapse_row_fixed_part_t *fixed); + +#endif // _SYNAPSE_DYNAMICS_H_ diff --git a/neural_modelling/src/meanfield/plasticity/synapse_dynamics_static_impl.c b/neural_modelling/src/meanfield/plasticity/synapse_dynamics_static_impl.c new file mode 100644 index 00000000000..75eb6a6548a --- /dev/null +++ b/neural_modelling/src/meanfield/plasticity/synapse_dynamics_static_impl.c @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/*! + * \file + * \brief This file contains the main interface for structural plasticity + * and some shared code. For the main implementation, see topographic_map_impl.c + * + * \author Petrut Bogdan + */ +#include "synapse_dynamics.h" +#include +#include + +//! ::synapse_index_bits + ::synapse_type_bits +static uint32_t synapse_type_index_bits; +//! Number of bits to hold the neuron index +static uint32_t synapse_index_bits; +//! Mask to extract the neuron index (has ::synapse_index_bits bits set) +static uint32_t synapse_index_mask; +//! Number of bits to hold the synapse type +static uint32_t synapse_type_bits; +//! Mask to extract the synapse type (has ::synapse_type_bits bits set) +static uint32_t synapse_type_mask; + +bool synapse_dynamics_initialise( + UNUSED address_t address, uint32_t n_neurons, uint32_t n_synapse_types, + UNUSED uint32_t *ring_buffer_to_input_buffer_left_shifts) { + uint32_t n_neurons_power_2 = n_neurons; + uint32_t log_n_neurons = 1; + if (n_neurons != 1) { + if (!is_power_of_2(n_neurons)) { + n_neurons_power_2 = next_power_of_2(n_neurons); + } + log_n_neurons = ilog_2(n_neurons_power_2); + } + uint32_t n_synapse_types_power_2 = n_synapse_types; + synapse_type_bits = 1; + if (n_synapse_types != 1) { + if (!is_power_of_2(n_synapse_types)) { + n_synapse_types_power_2 = next_power_of_2(n_synapse_types); + } + synapse_type_bits = ilog_2(n_synapse_types_power_2); + } + synapse_type_index_bits = log_n_neurons + synapse_type_bits; + synapse_index_bits = log_n_neurons; + synapse_index_mask = (1 << synapse_index_bits) - 1; + synapse_type_mask = (1 << synapse_type_bits) - 1; + return true; +} + +//--------------------------------------- +void synapse_dynamics_process_post_synaptic_event( + UNUSED uint32_t time, UNUSED index_t neuron_index) { +} + +//--------------------------------------- +bool synapse_dynamics_process_plastic_synapses( + UNUSED synapse_row_plastic_data_t *plastic_region_data, + UNUSED synapse_row_fixed_part_t *fixed_region, + UNUSED weight_t *ring_buffer, UNUSED uint32_t time) { + log_error("There should be no plastic synapses!"); + return false; +} + +//--------------------------------------- +input_t synapse_dynamics_get_intrinsic_bias( + UNUSED uint32_t time, UNUSED index_t neuron_index) { + return ZERO; +} + +void synapse_dynamics_print_plastic_synapses( + UNUSED synapse_row_plastic_data_t *plastic_region_data, + UNUSED synapse_row_fixed_part_t *fixed_region, + UNUSED uint32_t *ring_buffer_to_input_left_shifts) { +} + +uint32_t synapse_dynamics_get_plastic_pre_synaptic_events(void) { + return 0; +} + +uint32_t synapse_dynamics_get_plastic_saturation_count(void) { + return 0; +} + +bool synapse_dynamics_find_neuron( + uint32_t id, synaptic_row_t row, weight_t *weight, uint16_t *delay, + uint32_t *offset, uint32_t *synapse_type) { + synapse_row_fixed_part_t *fixed_region = synapse_row_fixed_region(row); + int32_t fixed_synapse = synapse_row_num_fixed_synapses(fixed_region); + uint32_t *synaptic_words = synapse_row_fixed_weight_controls(fixed_region); + + // Loop through plastic synapses + for (; fixed_synapse > 0; fixed_synapse--) { + + // Get next control word (auto incrementing) + // Check if index is the one I'm looking for + uint32_t synaptic_word = *synaptic_words++; + if (synapse_row_sparse_index(synaptic_word, synapse_index_mask) == id) { + *offset = synapse_row_num_fixed_synapses(fixed_region) - + fixed_synapse; + *weight = synapse_row_sparse_weight(synaptic_word); + *delay = synapse_row_sparse_delay(synaptic_word, + synapse_type_index_bits); + *synapse_type = synapse_row_sparse_type( + synaptic_word, synapse_index_bits, synapse_type_mask); + return true; + } + } + + return false; +} + +bool synapse_dynamics_remove_neuron(uint32_t offset, synaptic_row_t row) { + synapse_row_fixed_part_t *fixed_region = synapse_row_fixed_region(row); + int32_t fixed_synapse = synapse_row_num_fixed_synapses(fixed_region); + uint32_t *synaptic_words = synapse_row_fixed_weight_controls(fixed_region); + + // Delete control word at offset (contains weight) + synaptic_words[offset] = synaptic_words[fixed_synapse - 1]; + + // Decrement FF + fixed_region->num_fixed--; + return true; +} + +//! packing all of the information into the required static control word +static inline uint32_t _fixed_synapse_convert( + uint32_t id, weight_t weight, uint32_t delay, uint32_t type) { + uint32_t new_synapse = weight << (32 - SYNAPSE_WEIGHT_BITS); + new_synapse |= ((delay & ((1 << SYNAPSE_DELAY_BITS) - 1)) << + synapse_type_index_bits); + new_synapse |= ((type & ((1 << synapse_type_bits) - 1)) << + synapse_index_bits); + new_synapse |= (id & ((1 << synapse_type_index_bits) - 1)); + return new_synapse; +} + +bool synapse_dynamics_add_neuron( + uint32_t id, synaptic_row_t row, weight_t weight, + uint32_t delay, uint32_t type) { + synapse_row_fixed_part_t *fixed_region = synapse_row_fixed_region(row); + int32_t fixed_synapse = synapse_row_num_fixed_synapses(fixed_region); + uint32_t *synaptic_words = synapse_row_fixed_weight_controls(fixed_region); + uint32_t new_synapse = _fixed_synapse_convert(id, weight, delay, type); + + // Add control word at offset + synaptic_words[fixed_synapse] = new_synapse; + + // Increment FF + fixed_region->num_fixed++; + return true; +} + +uint32_t synapse_dynamics_n_connections_in_row( + synapse_row_fixed_part_t *fixed) { + return synapse_row_num_fixed_synapses(fixed); +} diff --git a/neural_modelling/src/meanfield/population_table/population_table.h b/neural_modelling/src/meanfield/population_table/population_table.h new file mode 100644 index 00000000000..963d03d680e --- /dev/null +++ b/neural_modelling/src/meanfield/population_table/population_table.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \dir +//! \brief Master population tables +//! \file +//! \brief Master pop(ulation) table API +#ifndef _POPULATION_TABLE_H_ +#define _POPULATION_TABLE_H_ + +#include +#include + +//! \brief the number of times a DMA resulted in 0 entries +extern uint32_t ghost_pop_table_searches; + +//! \brief the number of times packet isn't in the master pop table at all! +extern uint32_t invalid_master_pop_hits; + +//! \brief The number of bit fields which were not able to be read in due to +//! DTCM limits. +extern uint32_t failed_bit_field_reads; + +//! \brief The number of packets dropped because the bitfield filter says +//! they don't hit anything +extern uint32_t bit_field_filtered_packets; + +//! \brief Set up the table +//! \param[in] table_address: The address of the start of the table data +//! \param[in] synapse_rows_address: The address of the start of the synapse +//! data +//! \param[in] direct_rows_address: The address of the start of the direct +//! synapse data +//! \param[out] row_max_n_words: Updated with the maximum length of any row in +//! the table in words +//! \return True if the table was initialised successfully, False otherwise +bool population_table_initialise( + address_t table_address, address_t synapse_rows_address, + address_t direct_rows_address, uint32_t *row_max_n_words); + +//! \brief Initialise the bitfield filtering system. +//! \param[in] filter_region: Where the bitfield configuration is +//! \return True on success +bool population_table_load_bitfields(filter_region_t *filter_region); + +//! \brief Get the first row data for the given input spike +//! \param[in] spike: The spike received +//! \param[out] row_address: Updated with the address of the row +//! \param[out] n_bytes_to_transfer: Updated with the number of bytes to read +//! \return True if there is a row to read, False if not +bool population_table_get_first_address( + spike_t spike, synaptic_row_t* row_address, + size_t* n_bytes_to_transfer); + +//! \brief Get the next row data for a previously given spike. If no spike has +//! been given, return False. +//! \param[out] spike: The initiating spike +//! \param[out] row_address: Updated with the address of the row +//! \param[out] n_bytes_to_transfer: Updated with the number of bytes to read +//! \return True if there is a row to read, False if not +bool population_table_get_next_address( + spike_t *spike, synaptic_row_t* row_address, + size_t* n_bytes_to_transfer); + +#endif // _POPULATION_TABLE_H_ diff --git a/neural_modelling/src/meanfield/population_table/population_table_binary_search_impl.c b/neural_modelling/src/meanfield/population_table/population_table_binary_search_impl.c new file mode 100644 index 00000000000..d736a1a9c70 --- /dev/null +++ b/neural_modelling/src/meanfield/population_table/population_table_binary_search_impl.c @@ -0,0 +1,592 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Master population table implementation that uses binary search +#include "population_table.h" +#include +#include +#include + +//! bits in a word +#define BITS_PER_WORD 32 + +//! \brief The highest bit within the word +#define TOP_BIT_IN_WORD 31 + +//! \brief The flag for when a spike isn't in the master pop table (so +//! shouldn't happen) +#define NOT_IN_MASTER_POP_TABLE_FLAG -1 + +//! \brief The number of bits of address. +//! This is a constant as it is used more than once below. +#define N_ADDRESS_BITS 23 + +//! \brief The shift to apply to indirect addresses. +//! The address is in units of four words, so this multiplies by 16 (= up +//! shifts by 4) +#define INDIRECT_ADDRESS_SHIFT 4 + +//! \brief An entry in the master population table. +typedef struct master_population_table_entry { + //! The key to match against the incoming message + uint32_t key; + //! The mask to select the relevant bits of \p key for matching + uint32_t mask; + //! The index into ::address_list for this entry + uint32_t start: 15; + //! Flag to indicate if an extra_info struct is present + uint32_t extra_info_flag: 1; + //! The number of entries in ::address_list for this entry + uint32_t count: 16; +} master_population_table_entry; + +//! \brief A packed extra info (note: same size as address and row length) +typedef struct extra_info { + //! The mask to apply to the key once shifted get the core index + uint32_t core_mask: 10; + //! The number of words required for n_neurons + uint32_t n_words: 6; + //! The shift to apply to the key to get the core part (0-31) + uint32_t mask_shift: 5; + //! The number of neurons per core (up to 2048) + uint32_t n_neurons: 11; +} extra_info; + +//! \brief A packed address and row length (note: same size as extra info) +typedef struct { + //! the length of the row + uint32_t row_length : 8; + //! the address + uint32_t address : N_ADDRESS_BITS; + //! whether this is a direct/single address + uint32_t is_single : 1; +} address_and_row_length; + +//! \brief An entry in the address list is either an address and row length or extra +//! info if flagged. +typedef union { + address_and_row_length addr; + extra_info extra; +} address_list_entry; + +// An Invalid address and row length; used to keep indices aligned between +// delayed and undelayed tables +#define INVALID_ADDRESS ((1 << N_ADDRESS_BITS) - 1) + +//! \brief The memory layout in SDRAM of the first part of the population table +//! configuration. Address list data (array of ::address_and_row_length) is +//! packed on the end. +typedef struct { + uint32_t table_length; + uint32_t addr_list_length; + master_population_table_entry data[]; +} pop_table_config_t; + +//! The master population table. This is sorted. +static master_population_table_entry *master_population_table; + +//! The length of ::master_population_table +static uint32_t master_population_table_length; + +//! The array of information that points into the synaptic matrix +static address_list_entry *address_list; + +//! Base address for the synaptic matrix's indirect rows +static uint32_t synaptic_rows_base_address; + +//! Base address for the synaptic matrix's direct rows +static uint32_t direct_rows_base_address; + +//! \brief The last spike received +static spike_t last_spike = 0; + +//! \brief The last neuron id for the key +static uint32_t last_neuron_id = 0; + +//! the index for the next item in the ::address_list +static uint16_t next_item = 0; + +//! The number of relevant items remaining in the ::address_list +static uint16_t items_to_go = 0; + +//! The bitfield map +static bit_field_t *connectivity_bit_field = NULL; + +//! \brief the number of times a DMA resulted in 0 entries +uint32_t ghost_pop_table_searches = 0; + +//! \brief the number of times packet isnt in the master pop table at all! +uint32_t invalid_master_pop_hits = 0; + +//! \brief The number of bit fields which were not able to be read in due to +//! DTCM limits. +uint32_t failed_bit_field_reads = 0; + +//! \brief The number of packets dropped because the bitfield filter says +//! they don't hit anything +uint32_t bit_field_filtered_packets = 0; + +//! \name Support functions +//! \{ + +//! \brief Get the direct row address out of an entry +//! \param[in] entry: the table entry +//! \return a direct row address +static inline uint32_t get_direct_address(address_and_row_length entry) { + return entry.address + direct_rows_base_address; +} + +//! \brief Get the standard address offset out of an entry +//! \details The address is in units of four words, so this multiplies by 16 +//! (= up shifts by 4) +//! \param[in] entry: the table entry +//! \return a row address (which is an offset) +static inline uint32_t get_offset(address_and_row_length entry) { + return entry.address << INDIRECT_ADDRESS_SHIFT; +} + +//! \brief Get the standard address out of an entry +//! \param[in] entry: the table entry +//! \return a row address +static inline uint32_t get_address(address_and_row_length entry) { + return get_offset(entry) + synaptic_rows_base_address; +} + +//! \brief Get the length of the row from the entry +//! +//! Row lengths are stored offset by 1, to allow 1-256 length rows +//! +//! \param[in] entry: the table entry +//! \return the row length +static inline uint32_t get_row_length(address_and_row_length entry) { + return entry.row_length + 1; +} + +//! \brief Get the source core index from a spike +//! \param[in] extra: The extra info entry +//! \param[in] spike: The spike received +//! \return the source core index in the list of source cores +static inline uint32_t get_core_index(extra_info extra, spike_t spike) { + return (spike >> extra.mask_shift) & extra.core_mask; +} + +//! \brief Get the total number of neurons on cores which come before this core +//! \param[in] extra: The extra info entry +//! \param[in] spike: The spike received +//! \return the base neuron number of this core +static inline uint32_t get_core_sum(extra_info extra, spike_t spike) { + return get_core_index(extra, spike) * extra.n_neurons; +} + +//! \brief Get the total number of bits in bitfields for cores which came before +//! this core. +//! \param[in] extra: The extra info entry +//! \param[in] spike: The spike received +//! \return the base bitfield bit index of this core +static inline uint32_t get_bitfield_sum(extra_info extra, spike_t spike) { + return get_core_index(extra, spike) * extra.n_words * BITS_PER_WORD; +} + +//! \brief Get the source neuron ID for a spike given its table entry (without extra info) +//! \param[in] entry: the table entry +//! \param[in] spike: the spike +//! \return the neuron ID +static inline uint32_t get_neuron_id( + master_population_table_entry entry, spike_t spike) { + return spike & ~entry.mask; +} + +//! \brief Get the neuron id of the neuron on the source core, for a spike with +// extra info +//! \param[in] entry: the table entry +//! \param[in] extra_info: the extra info entry +//! \param[in] spike: the spike received +//! \return the source neuron id local to the core +static inline uint32_t get_local_neuron_id( + master_population_table_entry entry, extra_info extra, spike_t spike) { + return spike & ~(entry.mask | (extra.core_mask << extra.mask_shift)); +} + +//! \brief Prints the master pop table. +//! \details For debugging +static inline void print_master_population_table(void) { +#if log_level >= LOG_DEBUG + log_info("Master_population\n"); + for (uint32_t i = 0; i < master_population_table_length; i++) { + master_population_table_entry entry = master_population_table[i]; + log_info("key: 0x%08x, mask: 0x%08x", entry.key, entry.mask); + int count = entry.count; + int start = entry.start; + if (entry.extra_info_flag) { + extra_info extra = address_list[start].extra; + start += 1; + log_info(" core_mask: 0x%08x, core_shift: %u, n_neurons: %u, n_words: %u", + extra.core_mask, extra.mask_shift, extra.n_neurons, extra.n_words); + } + for (uint16_t j = start; j < (start + count); j++) { + address_and_row_length addr = address_list[j].addr; + if (addr.address == INVALID_ADDRESS) { + log_info(" index %d: INVALID", j); + } else if (!addr.is_single) { + log_info(" index %d: offset: %u, address: 0x%08x, row_length: %u", + j, get_offset(addr), get_address(addr), get_row_length(addr)); + } else { + log_info(" index %d: offset: %u, address: 0x%08x, single", + j, addr.address, get_direct_address(addr)); + } + } + } + log_info("Population table has %u entries", master_population_table_length); +#endif +} + +//! \brief Check if the entry is a match for the given key +//! \param[in] mp_i: The master population table entry index +//! \param[in] key: The key to check +//! \return: Whether the key matches the entry +static inline bool matches(uint32_t mp_i, uint32_t key) { + return (key & master_population_table[mp_i].mask) == + master_population_table[mp_i].key; +} + +//! \brief Print bitfields for debugging +//! \param[in] mp_i: The master population table entry index +//! \param[in] start: The first index of the bitfield to print +//! \param[in] end: The index after the last bitfield to print +//! \param[in] filters: The bitfields to print +static inline void print_bitfields(uint32_t mp_i, uint32_t start, + uint32_t end, filter_info_t *filters) { +#if LOG_LEVEL >= LOG_DEBUG + // print out the bit field for debug purposes + log_info("Bit field(s) for key 0x%08x:", master_population_table[mp_i].key); + uint32_t offset = 0; + for (uint32_t bf_i = start; bf_i < end; bf_i++) { + uint32_t n_words = get_bit_field_size(filters[bf_i].n_atoms); + for (uint32_t i = 0; i < n_words; i++) { + log_info("0x%08x", connectivity_bit_field[mp_i][offset + i]); + } + offset += n_words; + } +#else + use(mp_i); + use(start); + use(end); + use(filters); +#endif +} + +bool population_table_load_bitfields(filter_region_t *filter_region) { + + if (master_population_table_length == 0) { + return true; + } + // try allocating DTCM for starting array for bitfields + connectivity_bit_field = + spin1_malloc(sizeof(bit_field_t) * master_population_table_length); + if (connectivity_bit_field == NULL) { + log_warning( + "Couldn't initialise basic bit field holder. Will end up doing" + " possibly more DMA's during the execution than required." + " We required %d bytes where %d are available", + sizeof(bit_field_t) * master_population_table_length, + sark_heap_max(sark.heap, 0)); + return true; + } + + // Go through the population table, and the relevant bitfield list, both + // of which are ordered by key... + uint32_t bf_i = 0; + uint32_t n_filters = filter_region->n_filters; + filter_info_t* filters = filter_region->filters; + for (uint32_t mp_i = 0; mp_i < master_population_table_length; mp_i++) { + connectivity_bit_field[mp_i] = NULL; + + log_debug("Master pop key: 0x%08x, mask: 0x%08x", + master_population_table[mp_i].key, master_population_table[mp_i].mask); + +#ifdef LOG_DEBUG + // Sanity checking code; not needed in normal operation, and costs ITCM + // With both things being in key order, this should never happen... + if (bf_i < n_filters && + filters[bf_i].key < master_population_table[mp_i].key) { + log_error("Skipping bitfield %d for key 0x%08x", bf_i, filters[bf_i].key); + rt_error(RTE_SWERR); + } +#endif + + // While there is a match, keep track of the start and end; note this + // may recheck the first entry, but there might not be a first entry if + // we have already gone off the end of the bitfield array + uint32_t start = bf_i; + uint32_t n_words_total = 0; + uint32_t useful = 0; + log_debug("Starting with bit field %d with key 0x%08x", bf_i, filters[bf_i].key); + while (bf_i < n_filters && matches(mp_i, filters[bf_i].key)) { + log_debug("Using bit field %d with key 0x%08x, merged %d, redundant %d", + bf_i, filters[bf_i].key, filters[bf_i].merged, filters[bf_i].all_ones); + n_words_total += get_bit_field_size(filters[bf_i].n_atoms); + useful += !(filters[bf_i].merged || filters[bf_i].all_ones); + bf_i++; + } + + // If there is something to copy, copy them in now + log_debug("Ended with bit field %d with key 0x%08x, n_words %d, useful %d", + bf_i, filters[bf_i].key, n_words_total, useful); + if (bf_i != start && useful) { + // Try to allocate all the bitfields for this entry + connectivity_bit_field[mp_i] = spin1_malloc( + sizeof(bit_field_t) * n_words_total); + if (connectivity_bit_field[mp_i] == NULL) { + // If allocation fails, we can still continue + log_debug( + "Could not initialise bit field for key %d, packets with " + "that key will use a DMA to check if the packet targets " + "anything within this core. Potentially slowing down the " + "execution of neurons on this core.", + master_population_table[mp_i].key); + // There might be more than one that has failed + failed_bit_field_reads += bf_i - start; + } else { + // If allocation succeeds, copy the bitfields in + bit_field_t bf_pointer = &connectivity_bit_field[mp_i][0]; + for (uint32_t i = start; i < bf_i; i++) { + uint32_t n_words = get_bit_field_size(filters[i].n_atoms); + spin1_memcpy(bf_pointer, filters[i].data, n_words * sizeof(uint32_t)); + bf_pointer = &bf_pointer[n_words]; + } + + print_bitfields(mp_i, start, bf_i, filters); + } + } + } + return true; +} + +//! \brief Get the position in the master population table. +//! \param[in] spike: The spike received +//! \param[out] position: The position found (only if returns true) +//! \return True if there is a matching entry, False otherwise +static inline bool population_table_position_in_the_master_pop_array( + spike_t spike, uint32_t *position) { + uint32_t imin = 0; + uint32_t imax = master_population_table_length; + + while (imin < imax) { + uint32_t imid = (imax + imin) >> 1; + master_population_table_entry entry = master_population_table[imid]; + if ((spike & entry.mask) == entry.key) { + *position = imid; + return true; + } else if (entry.key < spike) { + + // Entry must be in upper part of the table + imin = imid + 1; + } else { + // Entry must be in lower part of the table + imax = imid; + } + } + return false; +} +//! \} + +//! \name API functions +//! \{ + +bool population_table_initialise( + address_t table_address, address_t synapse_rows_address, + address_t direct_rows_address, uint32_t *row_max_n_words) { + log_debug("Population_table_initialise: starting"); + pop_table_config_t *config = (pop_table_config_t *) table_address; + + master_population_table_length = config->table_length; + log_debug("Master pop table length is %d\n", master_population_table_length); + log_debug("Master pop table entry size is %d\n", + sizeof(master_population_table_entry)); + uint32_t n_master_pop_bytes = + master_population_table_length * sizeof(master_population_table_entry); + log_debug("Pop table size is %d\n", n_master_pop_bytes); + + // only try to malloc if there's stuff to malloc. + if (n_master_pop_bytes != 0) { + master_population_table = spin1_malloc(n_master_pop_bytes); + if (master_population_table == NULL) { + log_error("Could not allocate master population table"); + return false; + } + } + + uint32_t address_list_length = config->addr_list_length; + uint32_t n_address_list_bytes = + address_list_length * sizeof(address_list_entry); + + // only try to malloc if there's stuff to malloc. + if (n_address_list_bytes != 0) { + address_list = spin1_malloc(n_address_list_bytes); + if (address_list == NULL) { + log_error("Could not allocate master population address list"); + return false; + } + } + + log_debug("Pop table size: %u (%u bytes)", + master_population_table_length, n_master_pop_bytes); + log_debug("Address list size: %u (%u bytes)", + address_list_length, n_address_list_bytes); + + // Copy the master population table + spin1_memcpy(master_population_table, config->data, n_master_pop_bytes); + spin1_memcpy(address_list, &config->data[master_population_table_length], + n_address_list_bytes); + + // Store the base address + log_info("The stored synaptic matrix base address is located at: 0x%08x", + synapse_rows_address); + log_info("The direct synaptic matrix base address is located at: 0x%08x", + direct_rows_address); + synaptic_rows_base_address = (uint32_t) synapse_rows_address; + direct_rows_base_address = (uint32_t) direct_rows_address; + + *row_max_n_words = 0xFF + N_SYNAPSE_ROW_HEADER_WORDS; + + print_master_population_table(); + return true; +} + +bool population_table_get_first_address( + spike_t spike, synaptic_row_t *row_address, + size_t *n_bytes_to_transfer) { + // locate the position in the binary search / array + log_debug("Searching for key %d", spike); + + // check we don't have a complete miss + uint32_t position; + if (!population_table_position_in_the_master_pop_array(spike, &position)) { + invalid_master_pop_hits++; + log_debug("Ghost searches: %u\n", ghost_pop_table_searches); + log_debug("Spike %u (= %x): " + "Population not found in master population table", + spike, spike); + return false; + } + log_debug("position = %d", position); + + master_population_table_entry entry = master_population_table[position]; + if (entry.count == 0) { + log_debug("Spike %u (= %x): Population found in master population" + "table but count is 0", spike, spike); + } + + last_spike = spike; + next_item = entry.start; + items_to_go = entry.count; + uint32_t bit_field_id = 0; + if (entry.extra_info_flag) { + extra_info extra = address_list[next_item++].extra; + uint32_t local_neuron_id = get_local_neuron_id(entry, extra, spike); + last_neuron_id = local_neuron_id + get_core_sum(extra, spike); + bit_field_id = local_neuron_id + get_bitfield_sum(extra, spike); + } else { + last_neuron_id = get_neuron_id(entry, spike); + bit_field_id = last_neuron_id; + } + + // check we have a entry in the bit field for this (possible not to due to + // DTCM limitations or router table compression). If not, go to DMA check. + log_debug("Checking bit field"); + if (connectivity_bit_field != NULL && + connectivity_bit_field[position] != NULL) { + log_debug("Can be checked, bitfield is allocated"); + // check that the bit flagged for this neuron id does hit a + // neuron here. If not return false and avoid the DMA check. + if (!bit_field_test( + connectivity_bit_field[position], bit_field_id)) { + log_debug("Tested and was not set"); + bit_field_filtered_packets += 1; + items_to_go = 0; + return false; + } + log_debug("Was set, carrying on"); + } else { + log_debug("Bit field was not set up. " + "either its due to a lack of DTCM, or because the " + "bit field was merged into the routing table"); + } + + log_debug("spike = %08x, entry_index = %u, start = %u, count = %u", + spike, position, next_item, items_to_go); + + // A local address is used here as the interface requires something + // to be passed in but using the address of an argument is odd! + uint32_t local_spike_id; + bool get_next = population_table_get_next_address( + &local_spike_id, row_address, n_bytes_to_transfer); + + // tracks surplus DMAs + if (!get_next) { + log_debug("Found a entry which has a ghost entry for key %d", spike); + ghost_pop_table_searches++; + } + return get_next; +} + +bool population_table_get_next_address( + spike_t *spike, synaptic_row_t *row_address, + size_t *n_bytes_to_transfer) { + // If there are no more items in the list, return false + if (items_to_go == 0) { + return false; + } + + bool is_valid = false; + do { + address_and_row_length item = address_list[next_item].addr; + if (item.address != INVALID_ADDRESS) { + + // If the row is a direct row, indicate this by specifying the + // n_bytes_to_transfer is 0 + if (item.is_single) { + *row_address = (synaptic_row_t) (get_direct_address(item) + + (last_neuron_id * sizeof(uint32_t))); + *n_bytes_to_transfer = 0; + } else { + + uint32_t row_length = get_row_length(item); + uint32_t block_address = get_address(item); + uint32_t stride = (row_length + N_SYNAPSE_ROW_HEADER_WORDS); + uint32_t neuron_offset = last_neuron_id * stride * sizeof(uint32_t); + + *row_address = (synaptic_row_t) (block_address + neuron_offset); + *n_bytes_to_transfer = stride * sizeof(uint32_t); + log_debug("neuron_id = %u, block_address = 0x%.8x, " + "row_length = %u, row_address = 0x%.8x, n_bytes = %u", + last_neuron_id, block_address, row_length, *row_address, + *n_bytes_to_transfer); + *spike = last_spike; + } + is_valid = true; + } + + next_item++; + items_to_go--; + } while (!is_valid && (items_to_go > 0)); + + return is_valid; +} + +//! \} diff --git a/neural_modelling/src/meanfield/profile_tags.h b/neural_modelling/src/meanfield/profile_tags.h new file mode 100644 index 00000000000..67eb0d2d723 --- /dev/null +++ b/neural_modelling/src/meanfield/profile_tags.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Profiler tags +#pragma once + +//! Tags used when profiling sPyNNaker neuron code +enum profiler_tags_e { + PROFILER_TIMER, //!< timer + PROFILER_DMA_READ, //!< DMA read + PROFILER_INCOMING_SPIKE, //!< incoming spike handling + PROFILER_PROCESS_FIXED_SYNAPSES, //!< fixed synapse processing + PROFILER_PROCESS_PLASTIC_SYNAPSES //!< plastic synapse processing +}; diff --git a/neural_modelling/src/meanfield/regions.h b/neural_modelling/src/meanfield/regions.h new file mode 100644 index 00000000000..1c02486be9e --- /dev/null +++ b/neural_modelling/src/meanfield/regions.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Standard layout of DSG regions in neuron code. +//! +//! Note that not all models use all of these regions, but they all use the same +//! region identifier mapping. +#pragma once + +//! DSG region identifiers +typedef enum neuron_regions_e { + SYSTEM_REGION, //!< simulation system; 0 + NEURON_PARAMS_REGION, //!< neuron parameters; 1 + SYNAPSE_PARAMS_REGION, //!< synapse parameters; 2 + POPULATION_TABLE_REGION, //!< master population table; 3 + SYNAPTIC_MATRIX_REGION, //!< synaptic matrix; 4 + SYNAPSE_DYNAMICS_REGION, //!< synapse dynamics; 5 + STRUCTURAL_DYNAMICS_REGION, //!< structural dynamics; 6 + NEURON_RECORDING_REGION, //!< recording; 7 + PROVENANCE_DATA_REGION, //!< provenance; 8 + PROFILER_REGION, //!< profiling; 9 + CONNECTOR_BUILDER_REGION, //!< connection building; 10 + DIRECT_MATRIX_REGION, //!< direct synaptic matrix; 11 + BIT_FIELD_FILTER_REGION, //!< bitfield filter; 12 + BIT_FIELD_BUILDER, //!< bitfield builder parameters; 13 + BIT_FIELD_KEY_MAP //!< bitfield key map; 14 +} regions_e; diff --git a/neural_modelling/src/meanfield/spike_processing.c b/neural_modelling/src/meanfield/spike_processing.c new file mode 100644 index 00000000000..80b6654e378 --- /dev/null +++ b/neural_modelling/src/meanfield/spike_processing.c @@ -0,0 +1,521 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Implementation of non-inlined API in spike_processing.h +#include "spike_processing.h" +#include "population_table/population_table.h" +#include "synapse_row.h" +#include "synapses.h" +#include "direct_synapses.h" +#include "structural_plasticity/synaptogenesis_dynamics.h" +#include +#include +#include +#include + +//! DMA buffer structure combines the row read from SDRAM with information +//! about the read. +typedef struct dma_buffer { + //! Address in SDRAM to write back plastic region to + synaptic_row_t sdram_writeback_address; + + //! \brief Key of originating spike + //! \details used to allow row data to be re-used for multiple spikes + spike_t originating_spike; + + //! Number of bytes transferred in the read + uint32_t n_bytes_transferred; + + //! Row data + synaptic_row_t row; +} dma_buffer; + +//! The number of DMA Buffers to use +#define N_DMA_BUFFERS 2 + +//! DMA tags +enum spike_processing_dma_tags { + //! Tag of a DMA read of a full synaptic row + DMA_TAG_READ_SYNAPTIC_ROW, + //! Tag of a DMA write of the plastic region of a synaptic row + DMA_TAG_WRITE_PLASTIC_REGION +}; + +//! The current timer tick value +extern uint32_t time; + +//! True if the DMA "loop" is currently running +static volatile bool dma_busy; + +//! The DTCM buffers for the synapse rows +static dma_buffer dma_buffers[N_DMA_BUFFERS]; + +//! The index of the next buffer to be filled by a DMA +static uint32_t next_buffer_to_fill; + +//! The index of the buffer currently being filled by a DMA read +static uint32_t buffer_being_read; + +//! Number of outstanding synaptogenic rewirings +static volatile uint32_t rewires_to_do = 0; + +//! \brief The number of rewires to do when the DMA completes. +//! \details When a DMA is first set up, only this or ::dma_n_spikes can be 1 +//! with the other being 0. +static uint32_t dma_n_rewires; + +//! \brief The number of spikes to do when the DMA completes. +//! \details When a DMA is first set up, only this or ::dma_n_rewires can be 1 +//! with the other being 0. +static uint32_t dma_n_spikes; + +//! the number of DMA completes (used in provenance generation) +static uint32_t dma_complete_count; + +//! the number of spikes that were processed (used in provenance generation) +static uint32_t spike_processing_count; + +//! The number of successful rewires +static uint32_t n_successful_rewires; + +//! \brief How many packets were lost from the input buffer because of +//! late arrival +static uint32_t count_input_buffer_packets_late; + +//! tracker of how full the input buffer got. +static uint32_t biggest_fill_size_of_input_buffer; + +//! \brief Whether if we should clear packets from the input buffer at the +//! end of a timer tick. +static bool clear_input_buffers_of_late_packets; + +//! the number of packets received this time step +static struct { + uint32_t time; + uint32_t packets_this_time_step; +} p_per_ts_struct; + +//! the region to record the packets per timestep in +static uint32_t p_per_ts_region; + +/* PRIVATE FUNCTIONS - static for inlining */ + +//! \brief Perform a DMA read of a synaptic row +//! \param[in] row: Where in SDRAM to read the row from +//! \param[in] n_bytes_to_transfer: The size of the synaptic row +//! \param[in] spike: The spike that triggered this read +static inline void do_dma_read( + synaptic_row_t row, size_t n_bytes_to_transfer, spike_t spike) { + // Write the SDRAM address of the plastic region and the + // Key of the originating spike to the beginning of DMA buffer + dma_buffer *next_buffer = &dma_buffers[next_buffer_to_fill]; + next_buffer->sdram_writeback_address = row; + next_buffer->originating_spike = spike; + next_buffer->n_bytes_transferred = n_bytes_to_transfer; + + // Start a DMA transfer to fetch this synaptic row into current + // buffer + buffer_being_read = next_buffer_to_fill; + while (!spin1_dma_transfer( + DMA_TAG_READ_SYNAPTIC_ROW, row, next_buffer->row, DMA_READ, + n_bytes_to_transfer)) { + // Do Nothing + } + next_buffer_to_fill = (next_buffer_to_fill + 1) % N_DMA_BUFFERS; +} + +//! \brief Check if there is anything to do. If not, DMA is not busy +//! \param[out] row: +//! The address of the synaptic row that has been processed +//! \param[out] n_bytes_to_transfer: The size of the processed synaptic row +//! \param[out] spike: The spike being processed +//! \param[in,out] n_rewire: Accumulator of number of rewirings +//! \param[in,out] n_process_spike: Accumulator of number of processed spikes +//! \return True if there's something to do +static inline bool is_something_to_do( + synaptic_row_t *row, size_t *n_bytes_to_transfer, + spike_t *spike, uint32_t *n_rewire, uint32_t *n_process_spike) { + // Disable interrupts here as dma_busy modification is a critical section + uint cpsr = spin1_int_disable(); + + // Check for synaptic rewiring + while (rewires_to_do) { + rewires_to_do--; + spin1_mode_restore(cpsr); + if (synaptogenesis_dynamics_rewire(time, spike, row, + n_bytes_to_transfer)) { + *n_rewire += 1; + return true; + } + cpsr = spin1_int_disable(); + } + + // Is there another address in the population table? + spin1_mode_restore(cpsr); + if (population_table_get_next_address(spike, row, n_bytes_to_transfer)) { + *n_process_spike += 1; + return true; + } + cpsr = spin1_int_disable(); + + // track for provenance + uint32_t input_buffer_filled_size = in_spikes_size(); + if (biggest_fill_size_of_input_buffer < input_buffer_filled_size) { + biggest_fill_size_of_input_buffer = input_buffer_filled_size; + } + + // Are there any more spikes to process? + while (in_spikes_get_next_spike(spike)) { + // Enable interrupts while looking up in the master pop table, + // as this can be slow + spin1_mode_restore(cpsr); + if (population_table_get_first_address( + *spike, row, n_bytes_to_transfer)) { + synaptogenesis_spike_received(time, *spike); + *n_process_spike += 1; + return true; + } + + // Disable interrupts before checking if there is another spike + cpsr = spin1_int_disable(); + } + + // If nothing to do, the DMA is not busy + dma_busy = false; + + // Restore interrupts + spin1_mode_restore(cpsr); + return false; +} + +//! \brief Set up a new synaptic DMA read. +//! \details +//! If a current_buffer is passed in, any spike found that matches the +//! originating spike of the buffer will increment a count, and the DMA of that +//! row will be skipped. The number of times a row should be rewired and the +//! number of times synaptic processing should be done on a row is returned. +//! +//! Calls is_something_to_do(), do_direct_row() and do_dma_read() +//! \param[in] current_buffer: The current buffer, if any. +//! \param[in,out] n_rewires: Accumulator of number of rewirings +//! \param[in,out] n_synapse_processes: +//! Accumulator of number of synapses processed +static void setup_synaptic_dma_read(dma_buffer *current_buffer, + uint32_t *n_rewires, uint32_t *n_synapse_processes) { + // Set up to store the DMA location and size to read + synaptic_row_t row; + size_t n_bytes_to_transfer; + spike_t spike; + dma_n_spikes = 0; + dma_n_rewires = 0; + + // Keep looking if there is something to do until a DMA can be done + bool setup_done = false; + while (!setup_done && is_something_to_do(&row, &n_bytes_to_transfer, + &spike, &dma_n_rewires, &dma_n_spikes)) { + if (current_buffer != NULL && + current_buffer->sdram_writeback_address == row) { + // If we can reuse the row, add on what we can use it for + // Note that only one of these will have a value of 1 with the + // other being set to 0, but we add both as it is simple + *n_rewires += dma_n_rewires; + *n_synapse_processes += dma_n_spikes; + dma_n_rewires = 0; + dma_n_spikes = 0; + } else if (n_bytes_to_transfer == 0) { + // If the row is in DTCM, process the row now + synaptic_row_t single_fixed_synapse = + direct_synapses_get_direct_synapse(row); + bool write_back; + synapses_process_synaptic_row( + time, single_fixed_synapse, &write_back); + dma_n_rewires = 0; + dma_n_spikes = 0; + } else { + // If the row is in SDRAM, set up the transfer and we are done + do_dma_read(row, n_bytes_to_transfer, spike); + setup_done = true; + } + + // needs to be here to ensure that its only recording actual spike + // processing and not the surplus DMA requests. + spike_processing_count++; + } +} + +//! \brief Set up a DMA write of synaptic data. +//! \param[in] dma_buffer_index: Index of DMA buffer to use +//! \param[in] plastic_only: If false, write the whole synaptic row. +//! If true, only write the plastic data region of the synaptic row. +static inline void setup_synaptic_dma_write( + uint32_t dma_buffer_index, bool plastic_only) { + // Get pointer to current buffer + dma_buffer *buffer = &dma_buffers[dma_buffer_index]; + + // Get the number of plastic bytes and the write back address from the + // synaptic row + size_t write_size = buffer->n_bytes_transferred; + void *sdram_start_address = buffer->sdram_writeback_address; + void *dtcm_start_address = buffer->row; + if (plastic_only) { + write_size = synapse_row_plastic_size(buffer->row) * sizeof(uint32_t); + sdram_start_address = synapse_row_plastic_region( + buffer->sdram_writeback_address); + dtcm_start_address = synapse_row_plastic_region(buffer->row); + } + + log_debug("Writing back %u bytes of plastic region to %08x for spike %u", + write_size, sdram_start_address, buffer->originating_spike); + + // Start transfer + while (!spin1_dma_transfer(DMA_TAG_WRITE_PLASTIC_REGION, sdram_start_address, + dtcm_start_address, DMA_WRITE, write_size)) { + // Do Nothing + } +} + +//! \brief Called when a multicast packet is received +//! \param[in] key: The key of the packet. The spike. +//! \param payload: the payload of the packet. The count. +static void multicast_packet_received_callback(uint key, uint payload) { + p_per_ts_struct.packets_this_time_step += 1; + + // handle the 2 cases separately + if (payload == 0) { + log_debug( + "Received spike %x at %d, DMA Busy = %d", key, time, dma_busy); + // set to 1 to work with the loop. + payload = 1; + } else { + log_debug( + "Received spike %x with payload %d at %d, DMA Busy = %d", + key, payload, time, dma_busy); + } + + // cycle through the packet insertion + for (uint count = payload; count > 0; count--) { + in_spikes_add_spike(key); + } + + // If we're not already processing synaptic DMAs, + // flag pipeline as busy and trigger a feed event + // NOTE: locking is not used here because this is assumed to be FIQ + if (!dma_busy) { + log_debug("Sending user event for new spike"); + if (spin1_trigger_user_event(0, 0)) { + dma_busy = true; + } else { + log_warning("Could not trigger user event\n"); + } + } +} + +//! \brief Called when a DMA completes +//! \param unused: unused +//! \param[in] tag: What sort of DMA has finished? +static void dma_complete_callback(UNUSED uint unused, uint tag) { + + // increment the dma complete count for provenance generation + dma_complete_count++; + + log_debug("DMA transfer complete at time %u with tag %u", time, tag); + + // Get pointer to current buffer + uint32_t current_buffer_index = buffer_being_read; + dma_buffer *current_buffer = &dma_buffers[current_buffer_index]; + + // Start the next DMA transfer and get a count of the rewires and spikes + // that can be done on this row now (there might be more while the DMA + // was in progress). Note that either dma_n_rewires or dma_n_spikes is set + // to 1 here, with the other being 0. We take a copy of the count and this + // is the value added to for this processing, as setup_synaptic_dma will + // count repeats of the current spike + uint32_t n_rewires = dma_n_rewires; + uint32_t n_spikes = dma_n_spikes; + setup_synaptic_dma_read(current_buffer, &n_rewires, &n_spikes); + + // Assume no write back but assume any write back is plastic only + bool write_back = false; + bool plastic_only = true; + + // If rewiring, do rewiring first + for (uint32_t i = 0; i < n_rewires; i++) { + if (synaptogenesis_row_restructure(time, current_buffer->row)) { + write_back = true; + plastic_only = false; + n_successful_rewires++; + } + } + + // Process synaptic row repeatedly for any upcoming spikes + while (n_spikes > 0) { + + // Process synaptic row, writing it back if it's the last time + // it's going to be processed + bool write_back_now = false; + if (!synapses_process_synaptic_row( + time, current_buffer->row, &write_back_now)) { + log_error( + "Error processing spike 0x%.8x for address 0x%.8x" + " (local=0x%.8x)", + current_buffer->originating_spike, + current_buffer->sdram_writeback_address, + current_buffer->row); + + // Print out the row for debugging + address_t row = (address_t) current_buffer->row; + for (uint32_t i = 0; + i < (current_buffer->n_bytes_transferred >> 2); i++) { + log_error("%u: 0x%.8x", i, row[i]); + } + rt_error(RTE_SWERR); + } + + write_back |= write_back_now; + n_spikes--; + } + + if (write_back) { + setup_synaptic_dma_write(current_buffer_index, plastic_only); + } +} + +//! \brief Called when a user event is received +//! \param unused0: unused +//! \param unused1: unused +void user_event_callback(UNUSED uint unused0, UNUSED uint unused1) { + // Reset the counters as this is a new process + dma_n_rewires = 0; + dma_n_spikes = 0; + + if (buffer_being_read < N_DMA_BUFFERS) { + // If the DMA buffer is full of valid data, attempt to reuse it on the + // next data to be used, as this might be able to make use of the buffer + // without transferring data + dma_complete_callback(0, DMA_TAG_READ_SYNAPTIC_ROW); + } else { + // If the DMA buffer is invalid, just do the first transfer possible + setup_synaptic_dma_read(NULL, NULL, NULL); + } +} + +/* INTERFACE FUNCTIONS - cannot be static */ +//! \brief clears the input buffer of packets and records them +void spike_processing_clear_input_buffer(timer_t time) { + uint32_t n_spikes = in_spikes_size(); + if (clear_input_buffers_of_late_packets) { + spin1_dma_flush(); + in_spikes_clear(); + dma_busy = false; + } + + // Record the number of packets received last timer tick + p_per_ts_struct.time = time; + recording_record(p_per_ts_region, &p_per_ts_struct, sizeof(p_per_ts_struct)); + p_per_ts_struct.packets_this_time_step = 0; + + // Record the count whether clearing or not for provenance + count_input_buffer_packets_late += n_spikes; + +} + +bool spike_processing_initialise( // EXPORTED + size_t row_max_n_words, uint mc_packet_callback_priority, + uint user_event_priority, uint incoming_spike_buffer_size, + bool clear_input_buffers_of_late_packets_init, + uint32_t packets_per_timestep_region) { + // Allocate the DMA buffers + for (uint32_t i = 0; i < N_DMA_BUFFERS; i++) { + dma_buffers[i].row = spin1_malloc(row_max_n_words * sizeof(uint32_t)); + if (dma_buffers[i].row == NULL) { + log_error("Could not initialise DMA buffers"); + return false; + } + log_debug("DMA buffer %u allocated at 0x%08x", + i, dma_buffers[i].row); + } + dma_busy = false; + clear_input_buffers_of_late_packets = + clear_input_buffers_of_late_packets_init; + next_buffer_to_fill = 0; + buffer_being_read = N_DMA_BUFFERS; + p_per_ts_region = packets_per_timestep_region; + + // Allocate incoming spike buffer + if (!in_spikes_initialize_spike_buffer(incoming_spike_buffer_size)) { + return false; + } + + // Set up the callbacks + spin1_callback_on(MC_PACKET_RECEIVED, + multicast_packet_received_callback, mc_packet_callback_priority); + spin1_callback_on(MCPL_PACKET_RECEIVED, + multicast_packet_received_callback, mc_packet_callback_priority); + simulation_dma_transfer_done_callback_on( + DMA_TAG_READ_SYNAPTIC_ROW, dma_complete_callback); + spin1_callback_on(USER_EVENT, user_event_callback, user_event_priority); + + return true; +} + +uint32_t spike_processing_get_buffer_overflows(void) { // EXPORTED + // Check for buffer overflow + return in_spikes_get_n_buffer_overflows(); +} + +uint32_t spike_processing_get_dma_complete_count(void) { + return dma_complete_count; +} + +uint32_t spike_processing_get_spike_processing_count(void) { + return spike_processing_count; +} + +uint32_t spike_processing_get_successful_rewires(void) { // EXPORTED + return n_successful_rewires; +} + +uint32_t spike_processing_get_n_packets_dropped_from_lateness(void) { // EXPORTED + return count_input_buffer_packets_late; +} + +uint32_t spike_processing_get_max_filled_input_buffer_size(void) { // EXPORTED + return biggest_fill_size_of_input_buffer; +} + +//! \brief set the number of times spike_processing has to attempt rewiring +//! \return currently, always true +bool spike_processing_do_rewiring(int number_of_rewires) { + // disable interrupts + uint cpsr = spin1_int_disable(); + rewires_to_do += number_of_rewires; + + // If we're not already processing synaptic DMAs, + // flag pipeline as busy and trigger a feed event + if (!dma_busy) { + log_debug("Sending user event for rewiring"); + if (spin1_trigger_user_event(0, 0)) { + dma_busy = true; + } else { + log_debug("Could not trigger user event\n"); + } + } + // enable interrupts + spin1_mode_restore(cpsr); + return true; +} diff --git a/neural_modelling/src/meanfield/spike_processing.h b/neural_modelling/src/meanfield/spike_processing.h new file mode 100644 index 00000000000..0958e78b874 --- /dev/null +++ b/neural_modelling/src/meanfield/spike_processing.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Spike processing API +#ifndef _SPIKE_PROCESSING_H_ +#define _SPIKE_PROCESSING_H_ + +#include +#include +#include + +//! \brief Initialise the spike processing system +//! \param[in] row_max_n_bytes: The maximum size of a synaptic row +//! \param[in] mc_packet_callback_priority: +//! Multicast packet receive interrupt priority +//! \param[in] user_event_priority: User event interrupt priority +//! \param[in] incoming_spike_buffer_size: Size of buffer for receiving spikes +//! \param[in] packets_per_timestep_region: +//! The recording region to use for the packets per timestep +//! \return True if initialisation succeeded +bool spike_processing_initialise( + size_t row_max_n_bytes, uint mc_packet_callback_priority, + uint user_event_priority, uint incoming_spike_buffer_size, + bool clear_input_buffers_of_late_packets_init, + uint32_t packets_per_timestep_region); + +//! \brief Gets the number of times the input buffer has overflowed +//! \return the number of times the input buffer has overflowed +uint32_t spike_processing_get_buffer_overflows(void); + +//! \brief Gets the number of DMA's that were completed +//! \return the number of DMA's that were completed. +uint32_t spike_processing_get_dma_complete_count(void); + +//! \brief Gets the number of spikes that were processed +//! \return the number of spikes that were processed +uint32_t spike_processing_get_spike_processing_count(void); + +//! \brief Gets the number of successful rewires performed +//! \return the number of successful rewires +uint32_t spike_processing_get_successful_rewires(void); + +//! \brief Set the number of times spike_processing has to attempt rewiring. +//! \param[in] number_of_rewires: The number of rewirings to perform +//! \return currently always true +bool spike_processing_do_rewiring(int number_of_rewires); + +//! \brief return the number of packets dropped by the input buffer as they +//! arrived too late to be processed +//! \return the number of packets dropped. +uint32_t spike_processing_get_n_packets_dropped_from_lateness(void); + +//! \brief clears the input buffer of packets +//! \param[in] time: The current timestep +void spike_processing_clear_input_buffer(timer_t time); + +//! \brief returns how many packets were at max inside the input buffer at +//! any given point. +//! \return the max size the input buffer reached +uint32_t spike_processing_get_max_filled_input_buffer_size(void); + +#endif // _SPIKE_PROCESSING_H_ diff --git a/neural_modelling/src/meanfield/structural_plasticity/synaptogenesis/elimination/elimination.h b/neural_modelling/src/meanfield/structural_plasticity/synaptogenesis/elimination/elimination.h new file mode 100644 index 00000000000..4e4bb21b98f --- /dev/null +++ b/neural_modelling/src/meanfield/structural_plasticity/synaptogenesis/elimination/elimination.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \dir +//! \brief Synapse elimination algorithms +//! \file +//! \brief API for synapse elimination +#ifndef _ELIMINATION_H_ +#define _ELIMINATION_H_ + +#include +typedef struct elimination_params elimination_params_t; + +//! \brief Read and return an elimination parameter data structure from the +//! data stream +//! \param[in,out] data: The data stream to read from, updated to the new +//! position after the read is done +//! \return the read parameters data structure +elimination_params_t *synaptogenesis_elimination_init(uint8_t **data); + +//! \brief Elimination rule for synaptogenesis +//! \param[in,out] current_state: Pointer to current state +//! \param[in] params: The elimination rule configuration. +//! \param[in] time: Time of elimination +//! \param[in,out] row: The row to eliminate from +//! \return if row was modified +static inline bool synaptogenesis_elimination_rule( + current_state_t *current_state, const elimination_params_t *params, + uint32_t time, synaptic_row_t row); + +#endif // _ELIMINATION_H_ diff --git a/neural_modelling/src/meanfield/structural_plasticity/synaptogenesis/elimination/elimination_random_by_weight_impl.c b/neural_modelling/src/meanfield/structural_plasticity/synaptogenesis/elimination/elimination_random_by_weight_impl.c new file mode 100644 index 00000000000..abd3d0efb51 --- /dev/null +++ b/neural_modelling/src/meanfield/structural_plasticity/synaptogenesis/elimination/elimination_random_by_weight_impl.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Support code for elimination_random_by_weight_impl.h +#include "elimination_random_by_weight_impl.h" + +elimination_params_t *synaptogenesis_elimination_init(uint8_t **data) { + elimination_params_t *elim_params = + spin1_malloc(sizeof(elimination_params_t)); + if (elim_params == NULL) { + log_error("Out of memory when allocating parameters"); + rt_error(RTE_SWERR); + } + spin1_memcpy(elim_params, *data, sizeof(elimination_params_t)); + log_debug("Elimination random by weight prob_dep=%u prob_pot=%u thresh=%u", + elim_params->prob_elim_depression, + elim_params->prob_elim_potentiation, + elim_params->threshold); + *data += sizeof(elimination_params_t); + return elim_params; +} diff --git a/neural_modelling/src/meanfield/structural_plasticity/synaptogenesis/elimination/elimination_random_by_weight_impl.h b/neural_modelling/src/meanfield/structural_plasticity/synaptogenesis/elimination/elimination_random_by_weight_impl.h new file mode 100644 index 00000000000..3a6bb3d4bc2 --- /dev/null +++ b/neural_modelling/src/meanfield/structural_plasticity/synaptogenesis/elimination/elimination_random_by_weight_impl.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Synapse elimination by weighted random selection +#ifndef _ELIMINATION_RANDOM_BY_WEIGHT_IMPL_H_ +#define _ELIMINATION_RANDOM_BY_WEIGHT_IMPL_H_ + +#include "elimination.h" + +//! Configuration of synapse elimination rule +struct elimination_params { + //! Probability of elimination of depressed synapse + uint32_t prob_elim_depression; + //! Probability of elimination of potentiated synapse + uint32_t prob_elim_potentiation; + //! Threshold below which a synapse is depressed, and above which it is + //! potentiated + uint32_t threshold; +}; + +//! \brief Elimination rule for synaptogenesis +//! \param[in,out] current_state: Pointer to current state +//! \param[in] params: The elimination rule configuration. +//! \param[in] time: Time of elimination +//! \param[in,out] row: The row to eliminate from +//! \return if row was modified +static inline bool synaptogenesis_elimination_rule( + current_state_t *restrict current_state, + const elimination_params_t *params, + UNUSED uint32_t time, synaptic_row_t restrict row) { + uint32_t random_number = mars_kiss64_seed(*(current_state->local_seed)); + + // Is weight depressed? + if (current_state->weight < params->threshold && + random_number > params->prob_elim_depression) { + return false; + } + + // Is weight potentiated or unchanged? + if (current_state->weight >= params->threshold && + random_number > params->prob_elim_potentiation) { + return false; + } + + return sp_structs_remove_synapse(current_state, row); +} + +#endif // _ELIMINATION_RANDOM_BY_WEIGHT_IMPL_H_ diff --git a/neural_modelling/src/meanfield/structural_plasticity/synaptogenesis/formation/formation.h b/neural_modelling/src/meanfield/structural_plasticity/synaptogenesis/formation/formation.h new file mode 100644 index 00000000000..a8f25371e9f --- /dev/null +++ b/neural_modelling/src/meanfield/structural_plasticity/synaptogenesis/formation/formation.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \dir +//! \brief Synapse formation algorithms +//! \file +//! \brief API for synapse formation +#ifndef _FORMATION_H_ +#define _FORMATION_H_ + +#include +typedef struct formation_params formation_params_t; + +//! \brief Read and return an formation parameter data structure from the +//! data stream +//! \param[in,out] data: The data stream to read from, updated to the new +//! position after the read is done +//! \return the read parameters data structure +formation_params_t *synaptogenesis_formation_init(uint8_t **data); + +//! \brief Formation rule for synaptogenesis; picks what neuron in the +//! _current_ population will have a synapse added, and then performs the +//! addition. +//! \param[in] current_state: Pointer to current state +//! \param[in] params: Pointer to rewiring data +//! \param[in] time: Time of formation +//! \param[in] row: The row to form within +//! \return if row was modified +static inline bool synaptogenesis_formation_rule( + current_state_t *current_state, const formation_params_t *params, + uint32_t time, synaptic_row_t row); + +#endif // _FORMATION_H_ diff --git a/neural_modelling/src/meanfield/structural_plasticity/synaptogenesis/formation/formation_distance_dependent_impl.c b/neural_modelling/src/meanfield/structural_plasticity/synaptogenesis/formation/formation_distance_dependent_impl.c new file mode 100644 index 00000000000..61da6ea9a35 --- /dev/null +++ b/neural_modelling/src/meanfield/structural_plasticity/synaptogenesis/formation/formation_distance_dependent_impl.c @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Support code for formation_distance_dependent_impl.h +#include "formation_distance_dependent_impl.h" + +formation_params_t *synaptogenesis_formation_init(uint8_t **data) { + // Reference the parameters to read the sizes + formation_params_t *form_params = (formation_params_t *) *data; + uint32_t data_size = sizeof(formation_params_t) + (sizeof(uint16_t) * + (form_params->ff_prob_size + form_params->lat_prob_size)); + + // Allocate the space for the data and copy it in + form_params = spin1_malloc(data_size); + if (form_params == NULL) { + log_error("Out of memory when allocating parameters"); + rt_error(RTE_SWERR); + } + spin1_memcpy(form_params, *data, data_size); + log_debug("Formation distance dependent %u bytes, grid=(%u, %u), %u ff probs, %u lat probs", + data_size, form_params->grid_x, form_params->grid_y, + form_params->ff_prob_size, form_params->lat_prob_size); + *data += data_size; + + return form_params; +} diff --git a/neural_modelling/src/meanfield/structural_plasticity/synaptogenesis/formation/formation_distance_dependent_impl.h b/neural_modelling/src/meanfield/structural_plasticity/synaptogenesis/formation/formation_distance_dependent_impl.h new file mode 100644 index 00000000000..acc5ff9eca1 --- /dev/null +++ b/neural_modelling/src/meanfield/structural_plasticity/synaptogenesis/formation/formation_distance_dependent_impl.h @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Synapse formation using a distance-dependent rule +#ifndef _FORMATION_DISTANCE_DEPENDENT_H_ +#define _FORMATION_DISTANCE_DEPENDENT_H_ + +#include "formation.h" + +//! Largest value in a `uint16_t` +#define MAX_SHORT 65535 + +//! \brief Configuration of synapse formation rule +//! +//! Describes the size of grid containing the neurons (the total number of +//! neurons probably ought to be equal to or just a bit under \a grid_x × +//! \a grid_y), and two tables of distance-dependent connection probabilities. +//! The FF table describes ??? connection probabilities, and the LAT table +//! describes lateral connection probabilities. Both are keyed by the _square_ +//! of the inter-neuron distance. +//! +//! Note that both pre- and post-neurons are assumed to be on the same size of +//! grid, and the inter-layer distance is assumed to be constant (so it can be +//! accounted for in the construction of the tables). +struct formation_params { + //! Size of grid containing neurons, X-dimension + uint32_t grid_x; + //! Size of grid containing neurons, Y-dimension + uint32_t grid_y; + //! Reciprocal of grid_x + unsigned long fract grid_x_recip; + //! Reciprocal of grid_y + unsigned long fract grid_y_recip; + //! Size of FF probability table + uint32_t ff_prob_size; + //! Size of LAT probability table + uint32_t lat_prob_size; + //! Concatenated probability tables; first the FF table, then the LAT table + uint16_t prob_tables[]; +}; + +//! \brief abs function +//! \param[in] a: value (must not be `INT_MIN`) +//! \return Absolute value of \a a +static int my_abs(int a) { + return a < 0 ? -a : a; +} + +//! \brief Formation rule for synaptogenesis; picks what neuron in the +//! _current_ population will have a synapse added, and then performs the +//! addition. +//! \param[in] current_state: Pointer to current state +//! \param[in] params: Pointer to rewiring data +//! \param[in] time: Time of formation +//! \param[in] row: The row to form within +//! \return if row was modified +static inline bool synaptogenesis_formation_rule( + current_state_t *current_state, const formation_params_t *params, + UNUSED uint32_t time, synaptic_row_t row) { + // Compute distances + // To do this I need to take the DIV and MOD of the + // post-synaptic neuron ID, of the pre-synaptic neuron ID + // Compute the distance of these 2 measures + uint32_t pre_x, pre_y, post_x, post_y; + // Pre computation requires querying the table with global information + uint32_t pre_global_id = current_state->key_atom_info->lo_atom + + current_state->pre_syn_id; + uint32_t post_global_id = current_state->post_syn_id + + current_state->post_low_atom; + + if (params->grid_x > 1) { + pre_x = muliulr(pre_global_id, params->grid_x_recip); + post_x = muliulr(post_global_id, params->grid_x_recip); + } else { + pre_x = 0; + post_x = 0; + } + + if (params->grid_y > 1) { + uint32_t pre_y_div = muliulr(pre_global_id, params->grid_y_recip); + uint32_t post_y_div = muliulr(post_global_id, params->grid_y_recip); + pre_y = pre_global_id - (pre_y_div * params->grid_y); + post_y = post_global_id - (post_y_div * params->grid_y); + } else { + pre_y = 0; + post_y = 0; + } + + // With periodic boundary conditions + uint32_t delta_x, delta_y; + delta_x = my_abs(pre_x - post_x); + delta_y = my_abs(pre_y - post_y); + + if (delta_x > params->grid_x >> 1 && params->grid_x > 1) { + delta_x -= params->grid_x; + } + + if (delta_y > params->grid_y >> 1 && params->grid_y > 1) { + delta_y -= params->grid_y; + } + + uint32_t distance = delta_x * delta_x + delta_y * delta_y; + + // Distance based probability extracted from the appropriate LUT + uint16_t probability; + int16_t controls = current_state->pre_population_info->sp_control; + if (!(controls & IS_CONNECTION_LAT)) { + if (distance >= params->ff_prob_size) { + return false; + } + probability = params->prob_tables[distance]; + } else { + if (distance >= params->lat_prob_size) { + return false; + } + probability = params->prob_tables[params->ff_prob_size + distance]; + } + uint32_t r = rand_int(MAX_SHORT, *(current_state->local_seed)); + if (r > probability) { + return false; + } + + return sp_structs_add_synapse(current_state, row); +} + +#endif // _FORMATION_DISTANCE_DEPENDENT_H_ diff --git a/neural_modelling/src/meanfield/structural_plasticity/synaptogenesis/partner_selection/last_neuron_selection_impl.c b/neural_modelling/src/meanfield/structural_plasticity/synaptogenesis/partner_selection/last_neuron_selection_impl.c new file mode 100644 index 00000000000..fbd102f1a0d --- /dev/null +++ b/neural_modelling/src/meanfield/structural_plasticity/synaptogenesis/partner_selection/last_neuron_selection_impl.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Support code for last_neuron_selection_impl.h +#include "last_neuron_selection_impl.h" + +spike_t* last_spikes_buffer[2]; +uint32_t n_spikes[2]; +//! Size of each sub-array within ::last_spikes_buffer +uint32_t last_spikes_buffer_size; +//! The time of the most recently-considered spike +uint32_t last_time; + +void partner_init(uint8_t **data) { + last_spikes_buffer_size = ((uint32_t *) *data)[0]; + log_debug("Last neuron selection, buffer size = %u", last_spikes_buffer_size); + for (uint32_t i = 0; i < 2; i++) { + last_spikes_buffer[i] = + spin1_malloc(last_spikes_buffer_size * sizeof(spike_t)); + if (last_spikes_buffer[i] == NULL) { + log_error("Out of memory when creating last spikes buffer"); + rt_error(RTE_SWERR); + } + n_spikes[i] = 0; + } + *data += sizeof(uint32_t); +} diff --git a/neural_modelling/src/meanfield/structural_plasticity/synaptogenesis/partner_selection/last_neuron_selection_impl.h b/neural_modelling/src/meanfield/structural_plasticity/synaptogenesis/partner_selection/last_neuron_selection_impl.h new file mode 100644 index 00000000000..c10870437e9 --- /dev/null +++ b/neural_modelling/src/meanfield/structural_plasticity/synaptogenesis/partner_selection/last_neuron_selection_impl.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Recently spiked partners selection rule +#ifndef _LAST_NEURON_SELECTION_IMPL_H_ +#define _LAST_NEURON_SELECTION_IMPL_H_ + +#include "partner.h" +#include + +// Include debug header for log_info etc +#include + +//! \brief Spike accumulation buffers +//! \details Two arrays, one for current timestep, one for previous +extern spike_t* last_spikes_buffer[2]; +//! \brief Spike buffer counters +//! \details Two counters, one for current timestep, one for previous +extern uint32_t n_spikes[2]; + +//! \brief Notifies the rule that a spike has been received +//! \param[in] time: The time that the spike was received at +//! \param[in] spike: +//! The spike that was received (includes the sending neuron ID) +static inline void partner_spike_received(uint32_t time, spike_t spike) { + extern uint32_t last_spikes_buffer_size; + extern uint32_t last_time; + + uint32_t buffer = time & 0x1; + if (time != last_time) { + last_time = time; + n_spikes[buffer] = 0; + } + if (n_spikes[buffer] < last_spikes_buffer_size) { + last_spikes_buffer[buffer][n_spikes[buffer]++] = spike; + } +} + +//! \brief Choose the potential (remote) synaptic partner +//! \details Randomly (with uniform probability) select one of the last received +//! spikes, and uses the source neuron from that. +//! \param[in] time: The current time +//! \param[out] population_id: The ID of the other population +//! \param[out] sub_population_id: The ID of the subpopulation (corresponds to +//! remote SpiNNaker core handling the population) +//! \param[out] neuron_id: The ID of the neuron within the subpopulation +//! \param[out] spike: The spike that made this a meaningful choice +//! \param[out] m_pop_index: The master population table index +//! \return True if a choice was made +static inline bool potential_presynaptic_partner( + uint32_t time, uint32_t *restrict population_id, + uint32_t *restrict sub_population_id, uint32_t *restrict neuron_id, + spike_t *restrict spike, uint32_t *restrict m_pop_index) { + extern rewiring_data_t rewiring_data; + extern pre_pop_info_table_t pre_info; + + uint32_t buffer = (time - 1) & 0x1; + if (!n_spikes[buffer]) { + return false; + } + uint32_t offset = rand_int(n_spikes[buffer], rewiring_data.local_seed); + *spike = last_spikes_buffer[buffer][offset]; + return sp_structs_find_by_spike(&pre_info, *spike, neuron_id, + population_id, sub_population_id, m_pop_index); +} + +#endif // _LAST_NEURON_SELECTION_IMPL_H_ diff --git a/neural_modelling/src/meanfield/structural_plasticity/synaptogenesis/partner_selection/partner.h b/neural_modelling/src/meanfield/structural_plasticity/synaptogenesis/partner_selection/partner.h new file mode 100644 index 00000000000..c4d5b71cc3b --- /dev/null +++ b/neural_modelling/src/meanfield/structural_plasticity/synaptogenesis/partner_selection/partner.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \dir +//! \brief Partner selection rule +//! \file +//! \brief Partner selection rule common API +#ifndef _PARTNER_SELECTION_H_ +#define _PARTNER_SELECTION_H_ + +#include + +// MARS KISS 64 (RNG) +#include +// Bit manipulation after RNG +#include + +#include + +//! value to be returned when there is no valid partner selection +#define INVALID_SELECTION ((spike_t) - 1) + +//! \brief Initialise the partner selection rule +//! \param[in,out] data: A variable holding the location in SDRAM to configure +//! the rule from. Will be updated to point to the first location after the +//! configuration data. +void partner_init(uint8_t **data); + +//! \brief Notifies the rule that a spike has been received +//! \param[in] time: The time that the spike was received at +//! \param[in] spike: +//! The spike that was received (includes the sending neuron ID) +static inline void partner_spike_received(uint32_t time, spike_t spike); + +//! \brief Choose the potential (remote) synaptic partner +//! \param[in] time: The current time +//! \param[out] population_id: The ID of the other population +//! \param[out] sub_population_id: The ID of the subpopulation (corresponds to +//! remote SpiNNaker core handling the population) +//! \param[out] neuron_id: The ID of the neuron within the subpopulation +//! \param[out] spike: The spike that made this a meaningful choice +//! \param[out] m_pop_index: The master population table index +//! \return True if a choice was made +static inline bool potential_presynaptic_partner( + uint32_t time, uint32_t *restrict population_id, + uint32_t *restrict sub_population_id, + uint32_t *restrict neuron_id, spike_t *restrict spike, + uint32_t *restrict m_pop_index); + +#endif // _PARTNER_H_ diff --git a/neural_modelling/src/meanfield/structural_plasticity/synaptogenesis/partner_selection/random_selection_impl.c b/neural_modelling/src/meanfield/structural_plasticity/synaptogenesis/partner_selection/random_selection_impl.c new file mode 100644 index 00000000000..0ce723acdd9 --- /dev/null +++ b/neural_modelling/src/meanfield/structural_plasticity/synaptogenesis/partner_selection/random_selection_impl.c @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Support code for random_selection_impl.h +#include "random_selection_impl.h" + +void partner_init(UNUSED uint8_t **data) { +} diff --git a/neural_modelling/src/meanfield/structural_plasticity/synaptogenesis/partner_selection/random_selection_impl.h b/neural_modelling/src/meanfield/structural_plasticity/synaptogenesis/partner_selection/random_selection_impl.h new file mode 100644 index 00000000000..a7b252d4efc --- /dev/null +++ b/neural_modelling/src/meanfield/structural_plasticity/synaptogenesis/partner_selection/random_selection_impl.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Random partner selection rule +#ifndef _RANDOM_SELECTION_IMPL_H_ +#define _RANDOM_SELECTION_IMPL_H_ + +#include "partner.h" +#include +#include + +//! \brief Notifies the rule that a spike has been received +//! \details Not used by this rule +//! \param[in] time: The time that the spike was received at +//! \param[in] spike: +//! The spike that was received (includes the sending neuron ID) +static inline void partner_spike_received( + UNUSED uint32_t time, UNUSED spike_t spike) { +} + +//! \brief Choose the potential (remote) synaptic partner +//! \param[in] time: The current time +//! \param[out] population_id: The ID of the other population +//! \param[out] sub_population_id: The ID of the subpopulation (corresponds to +//! remote SpiNNaker core handling the population) +//! \param[out] neuron_id: The ID of the neuron within the subpopulation +//! \param[out] spike: The spike that made this a meaningful choice. +//! This rule synthesises this. +//! \param[out] m_pop_index: The master population table index. +//! \return True if a choice was made +static inline bool potential_presynaptic_partner( + UNUSED uint32_t time, uint32_t *restrict population_id, + uint32_t *restrict sub_population_id, uint32_t *restrict neuron_id, + spike_t *restrict spike, uint32_t *restrict m_pop_index) { + extern rewiring_data_t rewiring_data; + extern pre_pop_info_table_t pre_info; + + uint32_t pop_id = ulrbits(mars_kiss64_seed(rewiring_data.local_seed)) * + pre_info.no_pre_pops; + *population_id = pop_id; + pre_info_t *preapppop_info = pre_info.prepop_info[pop_id]; + + // Select presynaptic sub-population + uint32_t n_id = ulrbits(mars_kiss64_seed(rewiring_data.local_seed)) * + preapppop_info->total_no_atoms; + uint32_t subpop_id = 0; + uint32_t sum = 0; + for (uint32_t i = 0; i < preapppop_info->no_pre_vertices; i++) { + sum += preapppop_info->key_atom_info[i].n_atoms; + if (sum >= n_id) { + subpop_id = i; + break; + } + } + *sub_population_id = subpop_id; + + // Select a presynaptic neuron ID + n_id = ulrbits(mars_kiss64_seed(rewiring_data.local_seed)) * + preapppop_info->key_atom_info[subpop_id].n_atoms; + + *neuron_id = n_id; + *spike = preapppop_info->key_atom_info[subpop_id].key | n_id; + *m_pop_index = preapppop_info->key_atom_info[subpop_id].m_pop_index; + return true; +} + +#endif // _RANDOM_SELECTION_IMPL_H_ diff --git a/neural_modelling/src/meanfield/structural_plasticity/synaptogenesis/sp_structs.h b/neural_modelling/src/meanfield/structural_plasticity/synaptogenesis/sp_structs.h new file mode 100644 index 00000000000..15be5f64363 --- /dev/null +++ b/neural_modelling/src/meanfield/structural_plasticity/synaptogenesis/sp_structs.h @@ -0,0 +1,295 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \dir +//! \brief Structural plasticity through formation and elimination of synapses +//! \file +//! \brief Miscellaneous structures +#ifndef _SP_STRUCTS_H_ +#define _SP_STRUCTS_H_ + +#include +#include +#include +#include + +// Define the formation and elimination params +struct elimination_params; +struct formation_params; + +//! Flag: Is connection lateral? +#define IS_CONNECTION_LAT 1 + +//! Entry of map from post-connection to pre-connection neural indices +typedef struct post_to_pre_entry { + uint8_t pop_index; + uint8_t sub_pop_index; + uint16_t neuron_index; +} post_to_pre_entry; + +//! information per atom +typedef struct { + uint32_t key; + uint32_t mask; + uint32_t n_atoms; + uint32_t lo_atom; + uint32_t m_pop_index; +} key_atom_info_t; + +//! individual pre-synaptic sub-population information +typedef struct { + uint16_t no_pre_vertices; + uint16_t sp_control; + uint16_t delay_lo; + uint16_t delay_hi; + uint32_t weight; + uint32_t connection_type; + uint32_t total_no_atoms; + key_atom_info_t key_atom_info[]; +} pre_info_t; + +//! table of individual pre-synaptic information +typedef struct { + uint32_t no_pre_pops; + pre_info_t **prepop_info; +} pre_pop_info_table_t; + +//! parameters of the synaptic rewiring model +typedef struct { + uint32_t fast; + uint32_t p_rew; + uint32_t s_max; + uint32_t app_no_atoms; + uint32_t machine_no_atoms; + uint32_t low_atom; + uint32_t high_atom; + uint32_t with_replacement; + // the 2 seeds that are used: shared for sync, local for everything else + mars_kiss64_seed_t shared_seed; + mars_kiss64_seed_t local_seed; + uint32_t no_pre_pops; +} rewiring_data_t; + +//! struct representing the current state of rewiring +typedef struct { + //! Seed referenced from rewiring data + mars_kiss64_seed_t *local_seed; + //! Low atom copied from rewiring data + uint32_t post_low_atom; + // with_replacement copied from rewiring data + uint32_t with_replacement; + // what are the currently selecting pre- and post-synaptic neurons + uint32_t pre_syn_id; + uint32_t post_syn_id; + //! does the connection already exist + uint32_t element_exists; + // information extracted from the post to pre table + post_to_pre_entry *post_to_pre_table_entry; + pre_info_t *pre_population_info; + key_atom_info_t *key_atom_info; + post_to_pre_entry post_to_pre; + //! offset in synaptic row (if exists) + uint32_t offset; + //! current delay (if exists) + uint16_t delay; + //! current weight (if exists) + uint16_t weight; + //! synapse type + uint32_t synapse_type; +} current_state_t; + +//! Get a random unsigned integer up to (but not including) a given maximum +//! \param[in] max The maximum value allowed +//! \param[in] seed The random seed to use +//! \return The generated value +static inline uint32_t rand_int(uint32_t max, mars_kiss64_seed_t seed) { + return muliulr(max, ulrbits(mars_kiss64_seed(seed))); +} + +//! \brief unpack the spike into key and identifying information for the +//! neuron; Identify pop, sub-population and low and high atoms +//! \param[in] pre_pop_info_table: The prepopulation information table +//! \param[in] spike: The spike to look up the information from +//! \param[out] neuron_id: The ID of the neuron within its population +//! \param[out] population_id: The population ID +//! \param[out] sub_population_id: The ID of the sub-population +//! \param[out] m_pop_index: The master population table index +//! \return True if the information was found. +static inline bool sp_structs_find_by_spike( + const pre_pop_info_table_t *pre_pop_info_table, spike_t spike, + uint32_t *restrict neuron_id, uint32_t *restrict population_id, + uint32_t *restrict sub_population_id, uint32_t *restrict m_pop_index) { + // Amazing linear search inc. + // Loop over all populations + for (uint32_t i = 0; i < pre_pop_info_table->no_pre_pops; i++) { + const pre_info_t *pre_pop_info = pre_pop_info_table->prepop_info[i]; + + // Loop over all sub-populations and check if the KEY matches + // (with neuron ID masked out) + for (int j = 0; j < pre_pop_info->no_pre_vertices; j++) { + const key_atom_info_t *kai = &pre_pop_info->key_atom_info[j]; + if ((spike & kai->mask) == kai->key) { + *population_id = i; + *sub_population_id = j; + *neuron_id = spike & ~kai->mask; + *m_pop_index = kai->m_pop_index; + return true; + } + } + } + return false; +} + +//! \brief Get the sub-population id and sub-population-based neuron id given +//! the population id and the population-based neuron id +//! \param[in] pre_pop_info_table: The prepopulation information table +//! \param[in] population_id: The population ID +//! \param[in] pop_neuron_id: The ID of the neuron within the population +//! \param[out] sub_population_id: The ID of the sub-population +//! \param[out] sub_pop_neuron_id: +//! The ID of the neuron within the sub-population +//! \param[out] spike: The spike associated with communication from that neuron +//! \return True if the information was found. +static inline bool sp_structs_get_sub_pop_info( + const pre_pop_info_table_t *pre_pop_info_table, uint32_t population_id, + uint32_t pop_neuron_id, uint32_t *restrict sub_population_id, + uint32_t *restrict sub_pop_neuron_id, uint32_t *restrict spike) { + const pre_info_t *app_pop_info = + pre_pop_info_table->prepop_info[population_id]; + uint32_t neuron_id = pop_neuron_id; + for (uint32_t i = 0; i < app_pop_info->no_pre_vertices; i++) { + uint32_t n_atoms = app_pop_info->key_atom_info[i].n_atoms; + if (neuron_id < n_atoms) { + *sub_population_id = i; + *sub_pop_neuron_id = neuron_id; + *spike = app_pop_info->key_atom_info[i].key | neuron_id; + return true; + } + neuron_id -= n_atoms; + } + return false; +} + +//! \brief Removes a synapse from the relevant structures +//! \param[in,out] current_state: Describes what is to be done +//! \param[in,out] row: The row of the synaptic matrix to be updated +//! \return True if the synapse was removed +static inline bool sp_structs_remove_synapse( + current_state_t *restrict current_state, synaptic_row_t restrict row) { + if (!synapse_dynamics_remove_neuron(current_state->offset, row)) { + return false; + } + current_state->post_to_pre_table_entry->neuron_index = 0xFFFF; + return true; +} + +//! \brief Adds a synapse to the relevant structures +//! \param[in,out] current_state: Describes what is to be done +//! \param[in,out] row: The row of the synaptic matrix to be updated +//! \return True if the synapse was added +static inline bool sp_structs_add_synapse( + current_state_t *restrict current_state, synaptic_row_t restrict row) { + uint32_t appr_scaled_weight = current_state->pre_population_info->weight; + + uint32_t actual_delay; + uint32_t offset = current_state->pre_population_info->delay_hi - + current_state->pre_population_info->delay_lo; + actual_delay = rand_int(offset, *(current_state->local_seed)) + + current_state->pre_population_info->delay_lo; + + if (!synapse_dynamics_add_neuron( + current_state->post_syn_id, row, appr_scaled_weight, actual_delay, + current_state->pre_population_info->connection_type)) { + return false; + } + + // Critical: tell the compiler that this pointer is aligned so it doesn't + // internally convert the assignment to a memcpy(), which is a saving of + // hundreds of bytes... + post_to_pre_entry *ppentry = __builtin_assume_aligned( + current_state->post_to_pre_table_entry, 4); + *ppentry = current_state->post_to_pre; + return true; +} + +//! \brief Common code for structural plasticity initialisation. +//! \param[in] sdram_sp_address: Address of the configuration region. +//! \param[in,out] rewiring_data: +//! Address of the rewiring information structure to fill out. +//! \param[in,out] pre_info: +//! The pre-population information structure to fill out. +//! \param[out] post_to_pre_table: Variable to receive the address of the +//! post-population-to-pre-population mapping table that this function +//! discovers in the configuration region. +//! \return pointer to the next piece of memory after the common section of the +//! configuration region. +static inline uint8_t *sp_structs_read_in_common( + address_t sdram_sp_address, rewiring_data_t *rewiring_data, + pre_pop_info_table_t *pre_info, + post_to_pre_entry **post_to_pre_table) { + uint8_t *data = (uint8_t *) sdram_sp_address; + spin1_memcpy(rewiring_data, data, sizeof(rewiring_data_t)); + data += sizeof(rewiring_data_t); + log_debug("Topographic Map Impl, s_max=%u", rewiring_data->s_max); + + pre_info->no_pre_pops = rewiring_data->no_pre_pops; + log_debug(" no pre pops = %d", pre_info->no_pre_pops); + pre_info->prepop_info = spin1_malloc( + rewiring_data->no_pre_pops * sizeof(pre_info_t *)); + if (pre_info->prepop_info == NULL) { + log_error("Could not initialise pre population info"); + rt_error(RTE_SWERR); + } + for (uint32_t i = 0; i < rewiring_data->no_pre_pops; i++) { + pre_info->prepop_info[i] = (pre_info_t *) data; + uint32_t pre_size = (pre_info->prepop_info[i]->no_pre_vertices + * sizeof(key_atom_info_t)) + sizeof(pre_info_t); + pre_info->prepop_info[i] = spin1_malloc(pre_size); + if (pre_info->prepop_info[i] == NULL) { + log_error("Could not initialise pre population info %d", i); + rt_error(RTE_SWERR); + } + spin1_memcpy(pre_info->prepop_info[i], data, pre_size); + + log_debug("no_pre = %u, sp_control %u, " + "delay lo %u, delay hi %u, weight %d", + pre_info->prepop_info[i]->no_pre_vertices, + pre_info->prepop_info[i]->sp_control, + pre_info->prepop_info[i]->delay_lo, + pre_info->prepop_info[i]->delay_hi, + pre_info->prepop_info[i]->weight); + log_debug("connection_type = %d, total_no_atoms=%d", + pre_info->prepop_info[i]->connection_type, + pre_info->prepop_info[i]->total_no_atoms); + data += pre_size; + } + + *post_to_pre_table = (post_to_pre_entry *) data; + uint32_t n_elements = + rewiring_data->s_max * rewiring_data->machine_no_atoms; + + for (uint32_t i=0; i < n_elements; i++){ + log_debug("index %d, pop index %d, sub pop index %d, neuron_index %d", + i, post_to_pre_table[i]->pop_index, + post_to_pre_table[i]->sub_pop_index, + post_to_pre_table[i]->neuron_index); + } + data += n_elements * sizeof(post_to_pre_entry); + return (uint8_t *) data; +} + +#endif // _SP_STRUCTS_H_ diff --git a/neural_modelling/src/meanfield/structural_plasticity/synaptogenesis/topographic_map_impl.c b/neural_modelling/src/meanfield/structural_plasticity/synaptogenesis/topographic_map_impl.c new file mode 100644 index 00000000000..3a915bfb3af --- /dev/null +++ b/neural_modelling/src/meanfield/structural_plasticity/synaptogenesis/topographic_map_impl.c @@ -0,0 +1,328 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/*! \file + * \brief This file contains the main functions for probabilistic + * synaptogenesis. + * + * \author Petrut Bogdan + */ +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include + +// Interface for rules +#include "partner_selection/partner.h" +#include "elimination/elimination.h" +#include "formation/formation.h" + +//----------------------------------------------------------------------------- +// Structures and global data | +//----------------------------------------------------------------------------- + +//! the instantiation of the rewiring data +rewiring_data_t rewiring_data; + +//! inverse of synaptic matrix +static post_to_pre_entry *post_to_pre_table; + +//! pre-population information table +pre_pop_info_table_t pre_info; + +//! The formation parameters per pre-population +static formation_params_t **formation_params; + +//! The elimination parameters per pre-population +static elimination_params_t **elimination_params; + +//! \brief Current states in use. +//! +//! synaptogenesis_row_restructure() moves states from here to ::free_states +static circular_buffer current_state_queue; + +//! \brief Free current states. +//! +//! synaptogenesis_dynamics_rewire() moves states from here to +//! ::current_state_queue +static circular_buffer free_states; + +void print_post_to_pre_entry(void) { + uint32_t n_elements = + rewiring_data.s_max * rewiring_data.machine_no_atoms; + + for (uint32_t i=0; i < n_elements; i++) { + log_debug("index %d, pop index %d, sub pop index %d, neuron_index %d", + i, post_to_pre_table[i].pop_index, + post_to_pre_table[i].sub_pop_index, + post_to_pre_table[i].neuron_index); + } +} + +//----------------------------------------------------------------------------- +// Access helpers for circular buffers +//----------------------------------------------------------------------------- +static inline void _queue_state(current_state_t *state) { + if (__builtin_expect( + !circular_buffer_add(current_state_queue, (uint32_t) state), 0)) { + log_error("Could not add state (0x%08x) to queued states", state); + rt_error(RTE_SWERR); + } +} + +static inline current_state_t *_get_state(void) { + current_state_t *state; + if (__builtin_expect( + !circular_buffer_get_next(current_state_queue, (uint32_t *) &state), + 0)) { + log_error("Could not read a state!"); + rt_error(RTE_SWERR); + } + return state; +} + +static inline void _free_state(current_state_t *state) { + if (__builtin_expect( + !circular_buffer_add(free_states, (uint32_t) state), 0)) { + log_error("Could not add state (0x%08x) to free states", state); + rt_error(RTE_SWERR); + } +} + +static inline current_state_t *_alloc_state(void) { + current_state_t *state; + if (__builtin_expect( + !circular_buffer_get_next(free_states, (uint32_t *) &state), 0)) { + log_error("Ran out of states!"); + rt_error(RTE_SWERR); + } + return state; +} + +//----------------------------------------------------------------------------- +// Initialisation | +//----------------------------------------------------------------------------- + +bool synaptogenesis_dynamics_initialise(address_t sdram_sp_address) { + log_debug("SR init."); + + uint8_t *data = sp_structs_read_in_common( + sdram_sp_address, &rewiring_data, &pre_info, &post_to_pre_table); + + // Allocate current states + uint32_t n_states = 1; + if (rewiring_data.fast) { + n_states = rewiring_data.p_rew; + } + log_debug("Rewiring period %u, fast=%u, n_states=%u", + rewiring_data.p_rew, rewiring_data.fast, n_states); + // Add one to number of states as buffer wastes an entry + current_state_queue = circular_buffer_initialize(n_states + 1); + if (current_state_queue == NULL) { + log_error("Could not allocate current state queue"); + rt_error(RTE_SWERR); + } + // Add one to number of states as buffer wastes an entry + free_states = circular_buffer_initialize(n_states + 1); + if (free_states == NULL) { + log_error("Could not allocate free state queue"); + } + current_state_t *states = spin1_malloc(n_states * sizeof(current_state_t)); + if (states == NULL) { + log_error("Could not allocate states"); + rt_error(RTE_SWERR); + } + for (uint32_t i = 0; i < n_states; i++) { + _free_state(&states[i]); + } + + partner_init(&data); + + formation_params = spin1_malloc( + rewiring_data.no_pre_pops * sizeof(struct formation_params *)); + if (formation_params == NULL) { + log_error("Could not initialise formation parameters"); + rt_error(RTE_SWERR); + } + for (uint32_t i = 0; i < rewiring_data.no_pre_pops; i++) { + formation_params[i] = synaptogenesis_formation_init(&data); + } + + elimination_params = spin1_malloc( + rewiring_data.no_pre_pops * sizeof(struct elimination_params *)); + if (elimination_params == NULL) { + log_error("Could not initialise elimination parameters"); + rt_error(RTE_SWERR); + } + for (uint32_t i = 0; i < rewiring_data.no_pre_pops; i++) { + elimination_params[i] = synaptogenesis_elimination_init(&data); + } + + return true; +} + +bool synaptogenesis_dynamics_rewire( + uint32_t time, spike_t *spike, synaptic_row_t *synaptic_row, + uint32_t *n_bytes) { + + // Randomly choose a postsynaptic (application neuron) + uint32_t post_id = rand_int(rewiring_data.app_no_atoms, + rewiring_data.shared_seed); + + // Check if neuron is in the current machine vertex + if (post_id < rewiring_data.low_atom || + post_id > rewiring_data.high_atom) { + return false; + } + post_id -= rewiring_data.low_atom; + + // Select an arbitrary synaptic element for the neurons + uint32_t row_offset = post_id * rewiring_data.s_max; + uint32_t column_offset = rand_int(rewiring_data.s_max, + rewiring_data.local_seed); + uint32_t total_offset = row_offset + column_offset; + post_to_pre_entry entry = post_to_pre_table[total_offset]; + uint32_t pre_app_pop = 0, pre_sub_pop = 0, m_pop_index = 0, neuron_id = 0; + if (entry.neuron_index == 0xFFFF) { + if (!potential_presynaptic_partner(time, &pre_app_pop, &pre_sub_pop, + &neuron_id, spike, &m_pop_index)) { + return false; + } + } else { + pre_app_pop = entry.pop_index; + pre_sub_pop = entry.sub_pop_index; + neuron_id = entry.neuron_index; + } + pre_info_t *prepop_info = pre_info.prepop_info[pre_app_pop]; + key_atom_info_t *key_atom_info = &prepop_info->key_atom_info[pre_sub_pop]; + if (entry.neuron_index != 0xFFFF) { + *spike = key_atom_info->key | neuron_id; + m_pop_index = key_atom_info->m_pop_index; + } + + if (!population_table_get_first_address(*spike, synaptic_row, n_bytes)) { + log_error("FAIL@key %d", *spike); + rt_error(RTE_SWERR); + } + uint32_t index = 0; + while (index < m_pop_index) { + if (!population_table_get_next_address(spike, synaptic_row, n_bytes)) { + log_error("FAIL@key %d, index %d (failed at %d)", + *spike, m_pop_index, index); + rt_error(RTE_SWERR); + } + index++; + } + + // Saving current state + current_state_t *current_state = _alloc_state(); + current_state->pre_syn_id = neuron_id; + current_state->post_syn_id = post_id; + current_state->element_exists = entry.neuron_index != 0xFFFF; + current_state->post_to_pre_table_entry = &post_to_pre_table[total_offset]; + current_state->pre_population_info = prepop_info; + current_state->key_atom_info = key_atom_info; + current_state->post_to_pre.neuron_index = neuron_id; + current_state->post_to_pre.pop_index = pre_app_pop; + current_state->post_to_pre.sub_pop_index = pre_sub_pop; + current_state->local_seed = &rewiring_data.local_seed; + current_state->post_low_atom = rewiring_data.low_atom; + current_state->with_replacement = rewiring_data.with_replacement; + _queue_state(current_state); + return true; +} + +//! \brief Performs the actual restructuring of a row +//! \details Supporting function for synaptogenesis_row_restructure() +//! \param[in] time: The time of the restructure +//! \param[in] row: The row to restructure +//! \param[in] current_state: The current state of the world +//! \return True if the row was changed and needs to be written back +static inline bool row_restructure( + uint32_t time, synaptic_row_t restrict row, + current_state_t *restrict current_state) { + // the selected pre- and postsynaptic IDs are in current_state + if (current_state->element_exists) { + // find the offset of the neuron in the current row + if (!synapse_dynamics_find_neuron( + current_state->post_syn_id, row, + ¤t_state->weight, ¤t_state->delay, + ¤t_state->offset, ¤t_state->synapse_type)) { + log_debug("Post neuron %u not in row", current_state->post_syn_id); + return false; + } + return synaptogenesis_elimination_rule(current_state, + elimination_params[current_state->post_to_pre.pop_index], + time, row); + } else { + // Can't form if the row is full + uint32_t no_elems = synapse_dynamics_n_connections_in_row( + synapse_row_fixed_region(row)); + if (no_elems >= rewiring_data.s_max) { + log_debug("row is full"); + return false; + } else { + if (current_state->with_replacement) { + // A synapse can be added anywhere on the current row, so just do it + return synaptogenesis_formation_rule(current_state, + formation_params[current_state->post_to_pre.pop_index], time, row); + } else { + // A synapse cannot be added if one exists between the current pair of neurons + if (!synapse_dynamics_find_neuron( + current_state->post_syn_id, row, + &(current_state->weight), &(current_state->delay), + &(current_state->offset), &(current_state->synapse_type))) { + return synaptogenesis_formation_rule(current_state, + formation_params[current_state->post_to_pre.pop_index], time, row); + } else { + log_debug("Post neuron %u already in row", current_state->post_syn_id); + return false; + } + } + } + } +} + +bool synaptogenesis_row_restructure(uint32_t time, synaptic_row_t row) { + current_state_t *current_state = _get_state(); + bool return_value = row_restructure(time, row, current_state); + _free_state(current_state); + return return_value; +} + +int32_t synaptogenesis_rewiring_period(void) { + return rewiring_data.p_rew; +} + +bool synaptogenesis_is_fast(void) { + return rewiring_data.fast == 1; +} + +void synaptogenesis_spike_received(uint32_t time, spike_t spike) { + partner_spike_received(time, spike); +} diff --git a/neural_modelling/src/meanfield/structural_plasticity/synaptogenesis_dynamics.h b/neural_modelling/src/meanfield/structural_plasticity/synaptogenesis_dynamics.h new file mode 100644 index 00000000000..8edd3777b6a --- /dev/null +++ b/neural_modelling/src/meanfield/structural_plasticity/synaptogenesis_dynamics.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/*! + * \dir + * \brief Structural plasticity interface and algorithms + * \file + * \brief This file contains the main interface for structural plasticity + * \author Petrut Bogdan + */ +#ifndef _SYNAPTOGENESIS_DYNAMICS_H_ +#define _SYNAPTOGENESIS_DYNAMICS_H_ + +#include + +//! \brief Initialisation of synaptic rewiring (synaptogenesis) +//! parameters (random seed, spread of receptive field etc.) +//! \param[in] sdram_sp_address: Address of the start of the SDRAM region +//! which contains synaptic rewiring params. +//! \return Whether we were successful. +bool synaptogenesis_dynamics_initialise( + address_t sdram_sp_address); + +//! \brief Trigger the process of synaptic rewiring +//! \details Usually called on a timer registered in c_main() +//! \param[in] time: the current timestep +//! \param[out] spike: variable to hold the spike +//! \param[out] synaptic_row: variable to hold the address of the row +//! \param[out] n_bytes: variable to hold the size of the row +//! \return True if a row is to be transferred, false otherwise +bool synaptogenesis_dynamics_rewire(uint32_t time, + spike_t *spike, synaptic_row_t *synaptic_row, uint32_t *n_bytes); + +//! \brief Perform the actual restructuring of a row +//! \param[in] time: The time of the restructure +//! \param[in] row: The row to restructure +//! \return True if the row was changed and needs to be written back +bool synaptogenesis_row_restructure(uint32_t time, synaptic_row_t row); + +//! \brief Get the period of rewiring +//! \return Based on synaptogenesis_is_fast(), this can either be how many times +//! rewiring happens in a timestep, or how many timesteps have to pass until +//! rewiring happens. +int32_t synaptogenesis_rewiring_period(void); + +//! \brief Get whether rewiring is attempted multiple times per timestep +//! or after a number of timesteps. +//! \return true if the result of synaptogenesis_rewiring_period() is the number +//! of attempts to try per timestep. +bool synaptogenesis_is_fast(void); + +//! \brief Indicates that a spike has been received +//! \param[in] time: The time that the spike was received at +//! \param[in] spike: The received spike +void synaptogenesis_spike_received(uint32_t time, spike_t spike); + +//! Print a certain data object +void print_post_to_pre_entry(void); + +#endif // _SYNAPTOGENESIS_DYNAMICS_H_ diff --git a/neural_modelling/src/meanfield/structural_plasticity/synaptogenesis_dynamics_static_impl.c b/neural_modelling/src/meanfield/structural_plasticity/synaptogenesis_dynamics_static_impl.c new file mode 100644 index 00000000000..7e188945fe0 --- /dev/null +++ b/neural_modelling/src/meanfield/structural_plasticity/synaptogenesis_dynamics_static_impl.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/*! + * \file + * \brief This file contains the static (non-)implementation of synaptogenesis. + * \details No functionality is gained with this class. + */ +#include "synaptogenesis_dynamics.h" +#include + +bool synaptogenesis_dynamics_initialise(UNUSED address_t sdram_sp_address) { + return true; +} + +bool synaptogenesis_dynamics_rewire( + UNUSED uint32_t time, UNUSED spike_t *spike, + UNUSED synaptic_row_t *synaptic_row, UNUSED uint32_t *n_bytes) { + return false; +} + +bool synaptogenesis_row_restructure( + UNUSED uint32_t time, UNUSED synaptic_row_t row) { + return false; +} + +int32_t synaptogenesis_rewiring_period(void) { + return -1; +} + +bool synaptogenesis_is_fast(void) { + return false; +} + +void synaptogenesis_spike_received(UNUSED uint32_t time, UNUSED spike_t spike) { +} + +void print_post_to_pre_entry(void) { + return; +} diff --git a/neural_modelling/src/meanfield/synapse_row.h b/neural_modelling/src/meanfield/synapse_row.h new file mode 100644 index 00000000000..979a0fbe047 --- /dev/null +++ b/neural_modelling/src/meanfield/synapse_row.h @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/*! + * \file + * \brief implementation for handling the processing of synapse rows. + * + * \section row Synapse Row Representation + * ``` + * | Weight | Delay | Synapse Type | Neuron Index | + * |-------------------|------------------|-----------------|------------------| + * |SYNAPSE_WEIGHT_BITS|SYNAPSE_DELAY_BITS|SYNAPSE_TYPE_BITS|SYNAPSE_INDEX_BITS| + * | | | SYNAPSE_TYPE_INDEX_BITS | + * ``` + * The API interface supports: + * + * - synapse_row_plastic_size() + * - synapse_row_plastic_region() + * - synapse_row_fixed_region() + * - synapse_row_num_fixed_synapses() + * - synapse_row_num_plastic_controls() + * - synapse_row_plastic_controls() + * - synapse_row_fixed_weight_controls() + * - synapse_row_sparse_index() + * - synapse_row_sparse_type() + * - synapse_row_sparse_type_index() + * - synapse_row_sparse_delay() + * - synapse_row_sparse_weight() + * + * \section matrix Data Structure + * + * The data structure layout supported by this API is designed for + * mixed plastic and fixed synapse rows. + * + * The data structure is treated as an array of 32-bit words. + * Special meanings are ascribed to the 0th and 1st elements + * of the array. + * + * We are expecting the original source address in SDRAM to be + * in row[0]. The number of array elements in the plastic + * region is held in the upper part of row[1]. A tag to indicate + * the nature of the synaptic row structure is held in the lower + * part of row[1]. + * ``` + * 0: [ N = | ] + * 1: [ First word of plastic region ] + * ... + * N: [ Last word of plastic region ] + * N+1: [ First word of fixed region ] + * ... + * M: [ Last word of fixed region ] + * ``` + * + * \section fixed Fixed and Fixed-Plastic Regions + * + * Within the fixed-region extracted using the above API, fixed[0] + * contains the number of 32-bit fixed synaptic words, fixed[1] + * contains the number of 16-bit plastic synapse control words. + * (The weights for the plastic synapses are assumed to be stored + * in some learning-rule-specific format in the plastic region) + * ``` + * 0: [ F = Num fixed synapses ] + * 1: [ P = Size of plastic region in HALF-WORDS ] + * 2: [ First fixed synaptic word ] + * ... + * F+1: [ Last fixed synaptic word ] + * F+2: [ 1st plastic synapse control word|2nd plastic control word ] + * ... + * F+1+ceil(P/2): [ Last word of fixed region ] + * ``` + * Note that \p P is effectively rounded up to a multiple of two for storage + * purposes. + */ + +#ifndef _SYNAPSE_ROW_H_ +#define _SYNAPSE_ROW_H_ + +#include + +//! how many bits the synapse weight will take +#ifndef SYNAPSE_WEIGHT_BITS +#define SYNAPSE_WEIGHT_BITS 16 +#endif + +//! how many bits the synapse delay will take +#ifndef SYNAPSE_DELAY_BITS +#define SYNAPSE_DELAY_BITS 4 +#endif + +// Create some masks based on the number of bits +//! the mask for the synapse delay in the row +#define SYNAPSE_DELAY_MASK ((1 << SYNAPSE_DELAY_BITS) - 1) + +#ifdef SYNAPSE_WEIGHTS_SIGNED +//! Define the type of the weights +typedef __int_t(SYNAPSE_WEIGHT_BITS) weight_t; +#else +//! Define the type of the weights +typedef __uint_t(SYNAPSE_WEIGHT_BITS) weight_t; +#endif +//! Define the type of the control data +typedef uint16_t control_t; + +//! Number of header words per synaptic row +#define N_SYNAPSE_ROW_HEADER_WORDS 3 + +//! The type of the plastic-plastic part of the row +typedef struct { + size_t size; //!< The number of plastic words in `data` + uint32_t data[]; //!< The plastic words, followed by the fixed part +} synapse_row_plastic_part_t; + +//! The type of the fixed part of the row. The fixed-plastic part follows. +typedef struct { + size_t num_fixed; //!< The number of fixed synapses in `data` + size_t num_plastic; //!< The number of plastic controls in `data` + uint32_t data[]; //!< The data, first the fixed then the plastic +} synapse_row_fixed_part_t; + +typedef struct synapse_row_plastic_data_t synapse_row_plastic_data_t; + +//! \brief Get the size of the plastic region +//! \param[in] row: The synaptic row +//! \return The size of the plastic region of the row +static inline size_t synapse_row_plastic_size(const synaptic_row_t row) { + const synapse_row_plastic_part_t *the_row = + (const synapse_row_plastic_part_t *) row; + return the_row->size; +} + +//! \brief Get the address of the plastic region +//! \param[in] row: The synaptic row +//! \return Pointer to the plastic region of the row +static inline synapse_row_plastic_data_t *synapse_row_plastic_region( + synaptic_row_t row) { + synapse_row_plastic_part_t *the_row = (synapse_row_plastic_part_t *) row; + return (synapse_row_plastic_data_t *) the_row->data; +} + +//! \brief Get the address of the non-plastic (or fixed) region +//! \param[in] row: The synaptic row +//! \return Address of the fixed region of the row +static inline synapse_row_fixed_part_t *synapse_row_fixed_region( + synaptic_row_t row) { + synapse_row_plastic_part_t *the_row = (synapse_row_plastic_part_t *) row; + return (synapse_row_fixed_part_t *) &the_row->data[the_row->size]; +} + +//! \brief Get the number of fixed synapses in the row +//! \param[in] fixed: The fixed region of the synaptic row +//! \return Size of the fixed region of the row (in words) +static inline size_t synapse_row_num_fixed_synapses( + const synapse_row_fixed_part_t *fixed) { + return fixed->num_fixed; +} + +//! \brief Get the number of plastic controls in the row +//! \param[in] fixed: The fixed region of the synaptic row +//! \return Size of the fixed-plastic region of the row (in _half_ words) +static inline size_t synapse_row_num_plastic_controls( + const synapse_row_fixed_part_t *fixed) { + return fixed->num_plastic; +} + +//! \brief Get the array of plastic controls in the row +//! \param[in] fixed: The fixed region of the synaptic row +//! \return Address of the fixed-plastic region of the row +static inline control_t *synapse_row_plastic_controls( + synapse_row_fixed_part_t *fixed) { + return (control_t *) &fixed->data[fixed->num_fixed]; +} + +//! \brief The array of fixed weights in the row +//! \param[in] fixed: The fixed region of the synaptic row +//! \return Address of the fixed-fixed region of the row +static inline uint32_t *synapse_row_fixed_weight_controls( + synapse_row_fixed_part_t *fixed) { + return fixed->data; +} + +// The following are offset calculations into the ring buffers +//! \brief Get the index +//! \param[in] x: The value to decode +//! \param[in] synapse_index_mask: Mask for the synapse index (depends on type) +//! \return the index +static inline index_t synapse_row_sparse_index( + uint32_t x, uint32_t synapse_index_mask) { + return x & synapse_index_mask; +} + +//! \brief Get the type code +//! \param[in] x: The value to decode +//! \param[in] synapse_index_bits: +//! Number of bits for the synapse index (depends on type) +//! \param[in] synapse_type_mask: Mask for the synapse type (depends on type) +//! \return the type code +static inline index_t synapse_row_sparse_type( + uint32_t x, uint32_t synapse_index_bits, uint32_t synapse_type_mask) { + return (x >> synapse_index_bits) & synapse_type_mask; +} + +//! \brief Get the type and index +//! \param[in] x: The value to decode +//! \param[in] synapse_type_index_mask: +//! Mask for the synapse type and index (depends on type) +//! \return the type and index (packed in the low bits of a word) +static inline index_t synapse_row_sparse_type_index( + uint32_t x, uint32_t synapse_type_index_mask) { + return x & synapse_type_index_mask; +} + +//! \brief Get the delay from an encoded synapse descriptor +//! \param[in] x: The value to decode +//! \param[in] synapse_type_index_bits: +//! Number of bits for the synapse type and index (depends on type) +//! \return the delay +static inline index_t synapse_row_sparse_delay( + uint32_t x, uint32_t synapse_type_index_bits) { + return (x >> synapse_type_index_bits) & SYNAPSE_DELAY_MASK; +} + +//! \brief Get the weight from an encoded synapse descriptor +//! \param[in] x: The value to decode +//! \return the weight +static inline weight_t synapse_row_sparse_weight(uint32_t x) { + return x >> (32 - SYNAPSE_WEIGHT_BITS); +} + +#endif // SYNAPSE_ROW_H diff --git a/neural_modelling/src/meanfield/synapse_types/synapse_types.h b/neural_modelling/src/meanfield/synapse_types/synapse_types.h new file mode 100644 index 00000000000..6ab49058f33 --- /dev/null +++ b/neural_modelling/src/meanfield/synapse_types/synapse_types.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \dir +//! \brief Synaptic behaviour types +//! \file +//! \brief API for synaptic behaviour types +//! (see also \ref src/neuron/input_types) +#ifndef _SYNAPSE_TYPES_H_ +#define _SYNAPSE_TYPES_H_ + +#include +#include + +// Forward declaration of real type +struct synapse_param_t; +typedef struct synapse_param_t synapse_param_t; + +//! Forward declaration of synapse type (creates a definition for a pointer +//! to a synapse type parameter struct +typedef synapse_param_t *synapse_param_pointer_t; + +//! \brief decays the stuff thats sitting in the input buffers +//! as these have not yet been processed and applied to the neuron. +//! +//! This is to compensate for the valve behaviour of a synapse +//! in biology (spike goes in, synapse opens, then closes slowly). +//! \param[in,out] parameters: the parameters to update +static void synapse_types_shape_input(synapse_param_t *parameters); + +//! \brief adds the inputs for a give timer period to a given neuron that is +//! being simulated by this model +//! \param[in] synapse_type_index: the type of input that this input is to be +//! considered (aka excitatory or inhibitory etc) +//! \param[in,out] parameters: the parameters to update +//! \param[in] input: the inputs for that given synapse_type. +static void synapse_types_add_neuron_input( + index_t synapse_type_index, synapse_param_t *parameters, + input_t input); + +//! \brief extracts the excitatory input buffers from the buffers available +//! for a given neuron ID +//! \param[in] parameters: the pointer to the parameters to use +//! \return Pointer to array of excitatory input buffers for a given neuron ID. +static input_t* synapse_types_get_excitatory_input( + input_t *excitatory_response, synapse_param_t *parameters); + +//! \brief extracts the inhibitory input buffers from the buffers available +//! for a given neuron ID +//! \param[in] parameters: the pointer to the parameters to use +//! \return Pointer to array of inhibitory input buffers for a given neuron ID. +static input_t* synapse_types_get_inhibitory_input( + input_t *inhibitory_response, synapse_param_t *parameters); + +//! \brief returns a human readable character for the type of synapse. +//! +//! Examples would be `X` = excitatory types, `I` = inhibitory types, etc. +//! +//! \param[in] synapse_type_index: the synapse type index +//! (there is a specific index interpretation in each synapse type) +//! \return a human readable character representing the synapse type. +static const char *synapse_types_get_type_char(index_t synapse_type_index); + +//! \brief prints the parameters of the synapse type +//! \param[in] parameters: the pointer to the parameters to print +static void synapse_types_print_parameters( + synapse_param_t *parameters); + +//! \brief prints the input for a neuron ID given the available inputs +//! currently only executed when the models are in debug mode, as the prints +//! are controlled from the synapses.c print_inputs() method. +//! \param[in] parameters: the pointer to the parameters to print +static void synapse_types_print_input(synapse_param_t *parameters); + +#endif // _SYNAPSE_TYPES_H_ diff --git a/neural_modelling/src/meanfield/synapse_types/synapse_types_alpha_impl.h b/neural_modelling/src/meanfield/synapse_types/synapse_types_alpha_impl.h new file mode 100644 index 00000000000..6486b5ed295 --- /dev/null +++ b/neural_modelling/src/meanfield/synapse_types/synapse_types_alpha_impl.h @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/*! + * \file + * \brief implementation of synapse_types.h for an alpha synapse behaviour + */ + +#ifndef _ALPHA_SYNAPSE_H_ +#define _ALPHA_SYNAPSE_H_ + +//--------------------------------------- +// Macros +//--------------------------------------- +//! \brief Number of bits to encode the synapse type +//! \details ceil(log2(#SYNAPSE_TYPE_COUNT)) +#define SYNAPSE_TYPE_BITS 1 +//! \brief Number of synapse types +//! \details #NUM_EXCITATORY_RECEPTORS + #NUM_INHIBITORY_RECEPTORS +#define SYNAPSE_TYPE_COUNT 2 + +//! Number of excitatory receptors +#define NUM_EXCITATORY_RECEPTORS 1 +//! Number of inhibitory receptors +#define NUM_INHIBITORY_RECEPTORS 1 + +#include +#include +#include "synapse_types.h" + +//--------------------------------------- +// Synapse parameters +//--------------------------------------- +//! Internal structure of an alpha-shaped synaptic input +typedef struct alpha_params_t { + input_t lin_buff; //!< buffer for linear term + input_t exp_buff; //!< buffer for exponential term + //! _τ_-1 pre-multiplied by dt + input_t dt_divided_by_tau_sqr; + decay_t decay; //!< Exponential decay multiplier + input_t q_buff; //!< Temporary value of input +} alpha_params_t; + +struct synapse_param_t { + alpha_params_t exc; //!< Excitatory synaptic input + alpha_params_t inh; //!< Inhibitory synaptic input +}; + +//! The supported synapse type indices +typedef enum { + EXCITATORY, //!< Excitatory synaptic input + INHIBITORY, //!< Inhibitory synaptic input +} synapse_alpha_input_buffer_regions; + +//--------------------------------------- +// Synapse shaping inline implementation +//--------------------------------------- + +//! \brief Applies alpha shaping to a parameter +//! \param[in,out] a_params: The parameter to shape +static inline void alpha_shaping(alpha_params_t* a_params) { + a_params->lin_buff = a_params->lin_buff + ( + a_params->q_buff * a_params->dt_divided_by_tau_sqr); + + // Update exponential buffer + a_params->exp_buff = decay_s1615(a_params->exp_buff, a_params->decay); +} + +//! \brief decays the stuff thats sitting in the input buffers as these have not +//! yet been processed and applied to the neuron. +//! +//! This is to compensate for the valve behaviour of a synapse in biology +//! (spike goes in, synapse opens, then closes slowly) +//! plus the leaky aspect of a neuron. +//! +//! \param[in,out] parameters: the parameters to update +static inline void synapse_types_shape_input( + synapse_param_t *parameters) { + alpha_shaping(¶meters->exc); + alpha_shaping(¶meters->inh); +#if 0 + log_debug("lin: %12.6k, exp: %12.6k, comb: %12.6k", + parameters->exc.lin_buff, + parameters->exc.exp_buff, + parameters->exc.lin_buff * parameters->exc.exp_buff); +#endif +} + +//! \brief helper function to add input for a given timer period to a given +//! neuron +//! \param[in] a_params: the parameter to update +//! \param[in] input: the input to add. +static inline void add_input_alpha(alpha_params_t *a_params, input_t input) { + a_params->q_buff = input; + + a_params->exp_buff = + decay_s1615(a_params->exp_buff, a_params->decay) + ONE; + + a_params->lin_buff = + (a_params->lin_buff + (input * a_params->dt_divided_by_tau_sqr)) + * (ONE - ONE/a_params->exp_buff); +} + +//! \brief adds the inputs for a give timer period to a given neuron that is +//! being simulated by this model +//! \details Add input from ring buffer. Zero if no spikes, otherwise one or +//! more weights +//! \param[in] synapse_type_index: the type of input that this input is to be +//! considered (aka excitatory or inhibitory etc) +//! \param[in,out] parameters: the parameters to update +//! \param[in] input: the inputs for that given synapse_type. +static inline void synapse_types_add_neuron_input( + index_t synapse_type_index, synapse_param_t *parameters, + input_t input) { + if (input > ZERO) { + switch (synapse_type_index) { + case EXCITATORY: + add_input_alpha(¶meters->exc, input); + break; + case INHIBITORY: + add_input_alpha(¶meters->inh, input); + break; + } + } +} + +//! \brief extracts the excitatory input buffers from the buffers available +//! for a given neuron ID +//! \param[in] parameters: the pointer to the parameters to use +//! \return Pointer to array of excitatory input buffers for a given neuron ID. +static inline input_t* synapse_types_get_excitatory_input( + input_t *excitatory_response, synapse_param_t *parameters) { + excitatory_response[0] = + parameters->exc.lin_buff * parameters->exc.exp_buff; + return &excitatory_response[0]; +} + +//! \brief extracts the inhibitory input buffers from the buffers available +//! for a given neuron ID +//! \param[in] parameters: the pointer to the parameters to use +//! \return Pointer to array of inhibitory input buffers for a given neuron ID. +static inline input_t* synapse_types_get_inhibitory_input( + input_t *inhibitory_response, synapse_param_t *parameters) { + inhibitory_response[0] = + parameters->inh.lin_buff * parameters->inh.exp_buff; + return &inhibitory_response[0]; +} + +//! \brief returns a human readable character for the type of synapse. +//! \details Examples would be `X` = excitatory types, `I` = inhibitory types, +//! etc. +//! \param[in] synapse_type_index: the synapse type index +//! (there is a specific index interpretation in each synapse type) +//! \return a human readable character representing the synapse type. +static inline const char *synapse_types_get_type_char( + index_t synapse_type_index) { + switch (synapse_type_index) { + case EXCITATORY: + return "X"; + case INHIBITORY: + return "I"; + default: + log_debug("did not recognise synapse type %i", synapse_type_index); + return "?"; + } +} + +//! \brief prints the input for a neuron ID given the available inputs +//! currently only executed when the models are in debug mode, as the prints +//! are controlled from the synapses.c print_inputs() method. +//! \param[in] parameters: the pointer to the parameters to print +static inline void synapse_types_print_input( + synapse_param_t *parameters) { + io_printf(IO_BUF, "%12.6k - %12.6k", + parameters->exc.lin_buff * parameters->exc.exp_buff, + parameters->inh.lin_buff * parameters->inh.exp_buff); +} + +//! \brief prints the parameters of the synapse type +//! \param[in] parameters: the pointer to the parameters to print +static inline void synapse_types_print_parameters(synapse_param_t *parameters) { + log_debug("-------------------------------------\n"); + log_debug("exc_response = %11.4k\n", + parameters->exc.lin_buff * parameters->exc.exp_buff); + log_debug("inh_response = %11.4k\n", + parameters->inh.lin_buff * parameters->inh.exp_buff); +} + +#endif // _ALPHA_SYNAPSE_H_ diff --git a/neural_modelling/src/meanfield/synapse_types/synapse_types_delta_impl.h b/neural_modelling/src/meanfield/synapse_types/synapse_types_delta_impl.h new file mode 100644 index 00000000000..1111c9e9793 --- /dev/null +++ b/neural_modelling/src/meanfield/synapse_types/synapse_types_delta_impl.h @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/*! + * \file + * \brief implementation of synapse_types.h for a delta decay to synapses. + * + * If we have combined excitatory/inhibitory synapses it will be + * because both excitatory and inhibitory synaptic time-constants + * (and thus propagators) are identical. + */ + +#ifndef _SYNAPSE_TYPES_DELTA_IMPL_H_ +#define _SYNAPSE_TYPES_DELTA_IMPL_H_ + +//--------------------------------------- +// Macros +//--------------------------------------- +//! \brief Number of bits to encode the synapse type +//! \details ceil(log2(#SYNAPSE_TYPE_COUNT)) +#define SYNAPSE_TYPE_BITS 1 +//! \brief Number of synapse types +//! \details #NUM_EXCITATORY_RECEPTORS + #NUM_INHIBITORY_RECEPTORS +#define SYNAPSE_TYPE_COUNT 2 + +//! Number of excitatory receptors +#define NUM_EXCITATORY_RECEPTORS 1 +//! Number of inhibitory receptors +#define NUM_INHIBITORY_RECEPTORS 1 + +#include +#include +#include "synapse_types.h" + +//--------------------------------------- +// Synapse parameters +//--------------------------------------- +//! A synaptic input shaped as a Dirac delta +typedef struct delta_params_t { + //! The synaptic input value + input_t synaptic_input_value; +} delta_params_t; + +//! Delta synapses support just a single excitatory and inhibitory input each +struct synapse_param_t { + delta_params_t exc; //!< Excitatory synaptic input + delta_params_t inh; //!< Inhibitory synaptic input +}; + +//! The supported synapse type indices +typedef enum { + EXCITATORY, //!< Excitatory synaptic input + INHIBITORY, //!< Inhibitory synaptic input +} synapse_delta_input_buffer_regions; + +//--------------------------------------- +// Synapse shaping inline implementation +//--------------------------------------- + +//! \brief Decays the stuff thats sitting in the input buffers. +//! \details +//! In this case, a delta shape means returning the value to zero +//! immediately. +//! \param[out] delta_param: the parameter to update +static inline void delta_shaping(delta_params_t *delta_param) { + delta_param->synaptic_input_value = 0; +} + +//! \brief decays the stuff thats sitting in the input buffers as these have not +//! yet been processed and applied to the neuron. +//! +//! This is to compensate for the valve behaviour of a synapse in biology +//! (spike goes in, synapse opens, then closes slowly) +//! plus the leaky aspect of a neuron. +//! +//! \param[in,out] parameters: the pointer to the parameters to use +static inline void synapse_types_shape_input( + synapse_param_t *parameters) { + delta_shaping(¶meters->exc); + delta_shaping(¶meters->inh); +} + +//! \brief helper function to add input for a given timer period to a given +//! neuron +//! \param[in,out] delta_param: the parameter to update +//! \param[in] input: the input to add. +static inline void add_input_delta( + delta_params_t *delta_param, input_t input) { + delta_param->synaptic_input_value += input; +} + +//! \brief adds the inputs for a give timer period to a given neuron that is +//! being simulated by this model +//! \param[in] synapse_type_index the type of input that this input is to be +//! considered (aka excitatory or inhibitory etc) +//! \param[in,out] parameters: the pointer to the parameters to use +//! \param[in] input the inputs for that given synapse_type. +static inline void synapse_types_add_neuron_input( + index_t synapse_type_index, synapse_param_t *parameters, + input_t input) { + switch (synapse_type_index) { + case EXCITATORY: + add_input_delta(¶meters->exc, input); + break; + case INHIBITORY: + add_input_delta(¶meters->inh, input); + break; + } +} + +//! \brief extracts the excitatory input buffers from the buffers available +//! for a given parameter set +//! \param[in] parameters: the pointer to the parameters to use +//! \return the excitatory input buffers for a given neuron ID. +static inline input_t *synapse_types_get_excitatory_input( + input_t *excitatory_response, synapse_param_t *parameters) { + excitatory_response[0] = parameters->exc.synaptic_input_value; + return &excitatory_response[0]; +} + +//! \brief extracts the inhibitory input buffers from the buffers available +//! for a given parameter set +//! \param[in] parameters: the pointer to the parameters to use +//! \return the inhibitory input buffers for a given neuron ID. +static inline input_t *synapse_types_get_inhibitory_input( + input_t *inhibitory_response, synapse_param_t *parameters) { + inhibitory_response[0] = parameters->inh.synaptic_input_value; + return &inhibitory_response[0]; +} + +//! \brief returns a human readable character for the type of synapse. +//! examples would be X = excitatory types, I = inhibitory types etc etc. +//! \param[in] synapse_type_index: the synapse type index +//! (there is a specific index interpretation in each synapse type) +//! \return a human readable character representing the synapse type. +static inline const char *synapse_types_get_type_char( + index_t synapse_type_index) { + switch (synapse_type_index) { + case EXCITATORY: + return "X"; + case INHIBITORY: + return "I"; + default: + log_debug("did not recognise synapse type %i", synapse_type_index); + return "?"; + } +} + +//! \brief prints the input for a neuron ID given the available inputs +//! currently only executed when the models are in debug mode, as the prints +//! are controlled from the synapses.c print_inputs() method. +//! \param[in] parameters: the pointer to the parameters to use +static inline void synapse_types_print_input( + synapse_param_t *parameters) { + io_printf(IO_BUF, "%12.6k - %12.6k", + parameters->exc.synaptic_input_value, + parameters->inh.synaptic_input_value); +} + +//! \brief printer call +//! \param[in] parameters: the pointer to the parameters to print +static inline void synapse_types_print_parameters( + synapse_param_t *parameters) { + synapse_types_print_input(parameters); +} + +#endif // _SYNAPSE_TYPES_DELTA_IMPL_H_ diff --git a/neural_modelling/src/meanfield/synapse_types/synapse_types_dual_excitatory_exponential_impl.h b/neural_modelling/src/meanfield/synapse_types/synapse_types_dual_excitatory_exponential_impl.h new file mode 100644 index 00000000000..5160c867a53 --- /dev/null +++ b/neural_modelling/src/meanfield/synapse_types/synapse_types_dual_excitatory_exponential_impl.h @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/*! + * \file + * \brief implementation of synapse_types.h for a simple duel exponential decay + * to synapses. + * + * \details If we have combined excitatory_one/excitatory_two/inhibitory + * synapses it will be because both excitatory and inhibitory synaptic + * time-constants (and thus propogators) are identical. + */ + +#ifndef _SYNAPSE_TYPES_DUAL_EXCITATORY_EXPONENTIAL_IMPL_H_ +#define _SYNAPSE_TYPES_DUAL_EXCITATORY_EXPONENTIAL_IMPL_H_ + +//--------------------------------------- +// Macros +//--------------------------------------- +//! \brief Number of bits to encode the synapse type +//! \details ceil(log2(#SYNAPSE_TYPE_COUNT)) +#define SYNAPSE_TYPE_BITS 2 +//! \brief Number of synapse types +//! \details #NUM_EXCITATORY_RECEPTORS + #NUM_INHIBITORY_RECEPTORS +#define SYNAPSE_TYPE_COUNT 3 + +//! Number of excitatory receptors +#define NUM_EXCITATORY_RECEPTORS 2 +//! Number of inhibitory receptors +#define NUM_INHIBITORY_RECEPTORS 1 + +#include +#include +#include "synapse_types.h" + +//--------------------------------------- +// Synapse parameters +//--------------------------------------- +//! Parameters for an exponential decay +typedef struct exp_params_t { + decay_t decay; //!< Decay multiplier per timestep + decay_t init; //!< Initial decay factor + input_t synaptic_input_value; //!< The actual synaptic contribution +} exp_params_t; + +struct synapse_param_t { + exp_params_t exc; //!< First excitatory synaptic input + exp_params_t exc2; //!< Second excitatory synaptic input + exp_params_t inh; //!< Inhibitory synaptic input +}; + +//! The supported synapse type indices +typedef enum { + EXCITATORY_ONE, //!< First excitatory synaptic input + EXCITATORY_TWO, //!< Second excitatory synaptic input + INHIBITORY, //!< Inhibitory synaptic input +} synapse_dual_input_buffer_regions; + +//--------------------------------------- +// Synapse shaping inline implementation +//--------------------------------------- + +//! \brief Shapes a single parameter +//! \param[in,out] exp_param: The parameter to shape +static inline void exp_shaping(exp_params_t *exp_param) { + // decay value according to decay constant + exp_param->synaptic_input_value = + decay_s1615(exp_param->synaptic_input_value, exp_param->decay); +} + +//! \brief decays the stuff thats sitting in the input buffers as these have not +//! yet been processed and applied to the neuron. +//! +//! This is to compensate for the valve behaviour of a synapse in biology (spike +//! goes in, synapse opens, then closes slowly) plus the leaky aspect of a +//! neuron. +//! +//! \param[in,out] parameters: the parameters to update +static inline void synapse_types_shape_input(synapse_param_t *parameters) { + exp_shaping(¶meters->exc); + exp_shaping(¶meters->exc2); + exp_shaping(¶meters->inh); +} + +//! \brief helper function to add input for a given timer period to a given +//! neuron +//! \param[in,out] exp_param: the parameter to be updated +//! \param[in] input: the input to add. +static inline void add_input_exp(exp_params_t *exp_param, input_t input) { + exp_param->synaptic_input_value = exp_param->synaptic_input_value + + decay_s1615(input, exp_param->init); +} + +//! \brief adds the inputs for a give timer period to a given neuron that is +//! being simulated by this model +//! \param[in] synapse_type_index: the type of input that this input is to be +//! considered (aka excitatory or inhibitory etc) +//! \param[in,out] parameters: the pointer to the parameters to use +//! \param[in] input: the inputs for that given synapse_type. +static inline void synapse_types_add_neuron_input( + index_t synapse_type_index, synapse_param_t *parameters, + input_t input) { + switch (synapse_type_index) { + case EXCITATORY_ONE: + add_input_exp(¶meters->exc, input); + break; + case EXCITATORY_TWO: + add_input_exp(¶meters->exc2, input); + break; + case INHIBITORY: + add_input_exp(¶meters->inh, input); + break; + } +} + +//! \brief extracts the excitatory input buffers from the buffers available +//! for a given parameter set +//! \param[in] parameters: the pointer to the parameters to use +//! \return the excitatory input buffers for a given neuron ID. +static inline input_t* synapse_types_get_excitatory_input( + input_t *excitatory_response, synapse_param_t *parameters) { + excitatory_response[0] = parameters->exc.synaptic_input_value; + excitatory_response[1] = parameters->exc2.synaptic_input_value; + return &excitatory_response[0]; +} + +//! \brief extracts the inhibitory input buffers from the buffers available +//! for a given parameter set +//! \param[in] parameters: the pointer to the parameters to use +//! \return the inhibitory input buffers for a given neuron ID. +static inline input_t* synapse_types_get_inhibitory_input( + input_t *inhibitory_response, synapse_param_t *parameters) { + inhibitory_response[0] = parameters->inh.synaptic_input_value; + return &inhibitory_response[0]; +} + +//! \brief returns a human readable character for the type of synapse. +//! examples would be X = excitatory types, I = inhibitory types etc etc. +//! \param[in] synapse_type_index: the synapse type index +//! (there is a specific index interpretation in each synapse type) +//! \return a human readable character representing the synapse type. +static inline const char *synapse_types_get_type_char( + index_t synapse_type_index) { + switch (synapse_type_index) { + case EXCITATORY_ONE: + return "X1"; + case EXCITATORY_TWO: + return "X2"; + case INHIBITORY: + return "I"; + default: + log_debug("did not recognise synapse type %i", synapse_type_index); + return "?"; + } +} + +//! \brief prints the input for a neuron ID given the available inputs +//! currently only executed when the models are in debug mode, as the prints +//! are controlled from the synapses.c print_inputs() method. +//! \param[in] parameters: the pointer to the parameters to use +static inline void synapse_types_print_input( + synapse_param_t *parameters) { + io_printf(IO_BUF, "%12.6k + %12.6k - %12.6k", + parameters->exc.synaptic_input_value, + parameters->exc2.synaptic_input_value, + parameters->inh.synaptic_input_value); +} + +//! \brief printer call +//! \param[in] parameters: the pointer to the parameters to print +static inline void synapse_types_print_parameters( + synapse_param_t *parameters) { + log_info("exc_decay = %11.4k\n", parameters->exc.decay); + log_info("exc_init = %11.4k\n", parameters->exc.init); + log_info("exc2_decay = %11.4k\n", parameters->exc2.decay); + log_info("exc2_init = %11.4k\n", parameters->exc2.init); + log_info("inh_decay = %11.4k\n", parameters->inh.decay); + log_info("inh_init = %11.4k\n", parameters->inh.init); + log_info("gsyn_excitatory_initial_value = %11.4k\n", + parameters->exc.synaptic_input_value); + log_info("gsyn_excitatory2_initial_value = %11.4k\n", + parameters->exc2.synaptic_input_value); + log_info("gsyn_inhibitory_initial_value = %11.4k\n", + parameters->inh.synaptic_input_value); +} + +#endif // _SYNAPSE_TYPES_DUAL_EXCITATORY_EXPONENTIAL_IMPL_H_ diff --git a/neural_modelling/src/meanfield/synapse_types/synapse_types_exponential_impl.h b/neural_modelling/src/meanfield/synapse_types/synapse_types_exponential_impl.h new file mode 100644 index 00000000000..6b6f557f09b --- /dev/null +++ b/neural_modelling/src/meanfield/synapse_types/synapse_types_exponential_impl.h @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/*! + * \file + * \brief implementation of synapse_types.h for Exponential shaping + * + * \details This is used to give a simple exponential decay to synapses. + * + * If we have combined excitatory/inhibitory synapses it will be + * because both excitatory and inhibitory synaptic time-constants + * (and thus propagations) are identical. + */ + +#ifndef _SYNAPSE_TYPES_EXPONENTIAL_IMPL_H_ +#define _SYNAPSE_TYPES_EXPONENTIAL_IMPL_H_ + +//--------------------------------------- +// Macros +//--------------------------------------- +//! \brief Number of bits to encode the synapse type +//! \details ceil(log2(#SYNAPSE_TYPE_COUNT)) +#define SYNAPSE_TYPE_BITS 1 +//! \brief Number of synapse types +//! \details #NUM_EXCITATORY_RECEPTORS + #NUM_INHIBITORY_RECEPTORS +#define SYNAPSE_TYPE_COUNT 2 + +//! Number of excitatory receptors +#define NUM_EXCITATORY_RECEPTORS 1 +//! Number of inhibitory receptors +#define NUM_INHIBITORY_RECEPTORS 1 + +#include +#include +#include "synapse_types.h" + +//--------------------------------------- +// Synapse parameters +//--------------------------------------- +typedef struct exp_params_t { + decay_t decay; //!< Decay multiplier per timestep + decay_t init; //!< Initial decay factor + input_t synaptic_input_value; //!< The actual synaptic contribution +} exp_params_t; + +struct synapse_param_t { + exp_params_t exc; //!< Excitatory synaptic input + exp_params_t inh; //!< Inhibitory synaptic input +}; + +//! The supported synapse type indices +typedef enum { + EXCITATORY, //!< Excitatory synaptic input + INHIBITORY, //!< Inhibitory synaptic input +} exponential_synapse_input_buffer_regions; + +//--------------------------------------- +// Synapse shaping inline implementation +//--------------------------------------- + +//! \brief Shapes a single parameter +//! \param[in,out] exp_param: The parameter to shape +static inline void exp_shaping(exp_params_t *exp_param) { + // decay value according to decay constant + exp_param->synaptic_input_value = + decay_s1615(exp_param->synaptic_input_value, exp_param->decay); +} + +//! \brief decays the stuff thats sitting in the input buffers as these have not +//! yet been processed and applied to the neuron. +//! +//! This is to compensate for the valve behaviour of a synapse in biology +//! (spike goes in, synapse opens, then closes slowly) +//! plus the leaky aspect of a neuron. +//! +//! \param[in,out] parameters: the parameters to update +static inline void synapse_types_shape_input( + synapse_param_t *parameters) { + exp_shaping(¶meters->exc); + exp_shaping(¶meters->inh); +} + +//! \brief helper function to add input for a given timer period to a given +//! neuron +//! \param[in,out] exp_param: the pointer to the parameters to use +//! \param[in] input: the inputs to add. +static inline void add_input_exp(exp_params_t *exp_param, input_t input) { + exp_param->synaptic_input_value = exp_param->synaptic_input_value + + decay_s1615(input, exp_param->init); +} + +//! \brief adds the inputs for a give timer period to a given neuron that is +//! being simulated by this model +//! \param[in] synapse_type_index the type of input that this input is to be +//! considered (aka excitatory or inhibitory etc) +//! \param[in,out] parameters: the parameters to update +//! \param[in] input the inputs for that given synapse_type. +static inline void synapse_types_add_neuron_input( + index_t synapse_type_index, synapse_param_t *parameters, + input_t input) { + switch (synapse_type_index) { + case EXCITATORY: + add_input_exp(¶meters->exc, input); + break; + case INHIBITORY: + add_input_exp(¶meters->inh, input); + break; + } +} + +//! \brief extracts the excitatory input buffers from the buffers available +//! for a given parameter set +//! \param[in] parameters: the pointer to the parameters to use +//! \return the excitatory input buffers for a given neuron ID. +static inline input_t* synapse_types_get_excitatory_input( + input_t *excitatory_response, synapse_param_t *parameters) { + excitatory_response[0] = parameters->exc.synaptic_input_value; + return &excitatory_response[0]; +} + +//! \brief extracts the inhibitory input buffers from the buffers available +//! for a given parameter set +//! \param[in] parameters: the pointer to the parameters to use +//! \return the inhibitory input buffers for a given neuron ID. +static inline input_t* synapse_types_get_inhibitory_input( + input_t *inhibitory_response, synapse_param_t *parameters) { + inhibitory_response[0] = parameters->inh.synaptic_input_value; + return &inhibitory_response[0]; +} + +//! \brief returns a human readable character for the type of synapse. +//! examples would be X = excitatory types, I = inhibitory types etc etc. +//! \param[in] synapse_type_index: the synapse type index +//! (there is a specific index interpretation in each synapse type) +//! \return a human readable character representing the synapse type. +static inline const char *synapse_types_get_type_char( + index_t synapse_type_index) { + switch (synapse_type_index) { + case EXCITATORY: + return "X"; + case INHIBITORY: + return "I"; + default: + log_debug("did not recognise synapse type %i", synapse_type_index); + return "?"; + } +} + +//! \brief prints the input for a neuron ID given the available inputs +//! currently only executed when the models are in debug mode, as the prints +//! are controlled from the synapses.c print_inputs() method. +//! \param[in] parameters: the pointer to the parameters to use +static inline void synapse_types_print_input( + synapse_param_t *parameters) { + io_printf(IO_BUF, "%12.6k - %12.6k", + parameters->exc.synaptic_input_value, + parameters->inh.synaptic_input_value); +} + +//! \brief printer call +//! \param[in] parameters: the pointer to the parameters to print +static inline void synapse_types_print_parameters( + synapse_param_t *parameters) { + log_debug("exc_decay = %R\n", parameters->exc.decay); + log_debug("exc_init = %R\n", parameters->exc.init); + log_debug("inh_decay = %R\n", parameters->inh.decay); + log_debug("inh_init = %R\n", parameters->inh.init); + log_debug("gsyn_excitatory_initial_value = %11.4k\n", + parameters->exc.synaptic_input_value); + log_debug("gsyn_inhibitory_initial_value = %11.4k\n", + parameters->inh.synaptic_input_value); +} + +#endif // _SYNAPSE_TYPES_EXPONENTIAL_IMPL_H_ diff --git a/neural_modelling/src/meanfield/synapse_types/synapse_types_my_impl.h b/neural_modelling/src/meanfield/synapse_types/synapse_types_my_impl.h new file mode 100644 index 00000000000..525d8571d50 --- /dev/null +++ b/neural_modelling/src/meanfield/synapse_types/synapse_types_my_impl.h @@ -0,0 +1,161 @@ +/*! \file + * \brief implementation of synapse_types.h for Exponential shaping +* +* \details This is used to give a simple exponential decay to synapses. +* +* If we have combined excitatory/inhibitory synapses it will be +* because both excitatory and inhibitory synaptic time-constants +* (and thus propogators) are identical. +*/ + + +#ifndef _SYNAPSE_TYPES_MY_IMPL_H_ +#define _SYNAPSE_TYPES_MY_IMPL_H_ + +// This is currently used for decaying the neuron input +#include + +#include + +// TODO: Determine the number of bits required by the synapse type in the +// synapse row data structure (i.e. enough bits to represent all desired +// synapse types) +// e.g. 1 bit for 2 possible types such as excitatory and inhibitory +// This must match the number returned by the python method +// get_n_synapse_type_bits +#define SYNAPSE_TYPE_BITS 1 + +// TODO: Determine the number of synapse types required +// (e.g. 2 for excitatory and inhibitory)] +// This must match the number returned by the python method +// get_n_synapse_types +#define SYNAPSE_TYPE_COUNT 2 + +// TODO: Define the parameters required to compute the synapse shape +// The number of parameters here should match the number per neuron +// written by the python method write_synapse_parameters +typedef struct synapse_param_t { + REAL my_exc_decay; + REAL my_exc_init; + REAL my_inh_decay; + REAL my_inh_init; + input_t my_input_buffer_excitatory_value; + input_t my_input_buffer_inhibitory_value; +} synapse_param_t; + +// Define receptor split +#define NUM_EXCITATORY_RECEPTORS 1 +#define NUM_INHIBITORY_RECEPTORS 1 + +// Include this here after defining the above items +#include + +// This makes it easy to keep track of which is which +typedef enum input_buffer_regions { + EXCITATORY, INHIBITORY, +} input_buffer_regions; + +//! \brief Shapes the values input into the neurons +//! \param[in] pointer to parameters the synapse parameter pointer passed in +//! \return Nothing +static inline void synapse_types_shape_input( + synapse_param_t *parameters) { + + parameters->my_input_buffer_excitatory_value = decay_s1615( + parameters->my_input_buffer_excitatory_value, + parameters->my_exc_decay); + parameters->my_input_buffer_inhibitory_value = decay_s1615( + parameters->my_input_buffer_inhibitory_value, + parameters->my_inh_decay); +} + + +//! \brief Adds the initial value to an input buffer for this shaping. Allows +// the input to be scaled before being added. +//! \param[in-out] input_buffers the pointer to the input buffers +//! \param[in] synapse_type_index the index of the synapse type to add the +// value to +//! \param[in] pointer to parameters the synapse parameters passed in +//! \param[in] input the input to be added +//! \return None +static inline void synapse_types_add_neuron_input( + index_t synapse_type_index, synapse_param_t *parameters, + input_t input) { + if (synapse_type_index == EXCITATORY) { + parameters->my_input_buffer_excitatory_value = + parameters->my_input_buffer_excitatory_value + + decay_s1615(input, parameters->my_exc_init); + + } else if (synapse_type_index == INHIBITORY) { + parameters->my_input_buffer_inhibitory_value = + parameters->my_input_buffer_inhibitory_value + + decay_s1615(input, parameters->my_inh_init); + } +} + +//! \brief Gets the excitatory input for a given neuron +//! \param[in] pointer to parameters the synapse parameters passed in +//! \return the first entry in the array of excitatory input values +static inline input_t* synapse_types_get_excitatory_input( + input_t *excitatory_response, synapse_param_t *parameters) { + excitatory_response[0] = parameters->my_input_buffer_excitatory_value; + return &excitatory_response[0]; +} + +//! \brief Gets the inhibitory input for a given neuron +//! \param[in] pointer to parameters the synapse parameters passed in +//! \return the first entry in array of inhibitory input values +static inline input_t* synapse_types_get_inhibitory_input( + input_t *inhibitory_response, synapse_param_t *parameters) { + inhibitory_response[0] = parameters->my_input_buffer_inhibitory_value; + return &inhibitory_response[0]; +} + +//! \brief returns a human readable character for the type of synapse, for +// debug purposes +//! examples would be X = excitatory types, I = inhibitory types etc etc. +//! \param[in] synapse_type_index the synapse type index +//! \return a human readable character representing the synapse type. +static inline const char *synapse_types_get_type_char( + index_t synapse_type_index) { + + // TODO: Update with your synapse types + if (synapse_type_index == EXCITATORY) { + return "X"; + } else if (synapse_type_index == INHIBITORY) { + return "I"; + } else { + log_debug("Did not recognise synapse type %i", synapse_type_index); + return "?"; + } +} + +//! \brief prints the input for a neuron ID for debug purposes +//! \param[in] pointer to parameters the synapse parameters passed in +//! \return Nothing +static inline void synapse_types_print_input( + synapse_param_t *parameters) { + io_printf(IO_BUF, "%12.6k - %12.6k", + parameters->my_input_buffer_excitatory_value, + parameters->my_input_buffer_inhibitory_value); + // TODO: Does this function need the remaining parameters adding to it? +} + +//! \brief print parameters call +//! \param[in] parameter: the pointer to the parameters to print +//! \return Nothing +static inline void synapse_types_print_parameters( + synapse_param_t *parameters) { + + // TODO: Update to print your parameters + log_info("my_exc_decay = %R\n", (unsigned fract) parameters->my_exc_decay); + log_info("my_exc_init = %R\n", (unsigned fract) parameters->my_exc_init); + log_info("my_inh_decay = %R\n", (unsigned fract) parameters->my_inh_decay); + log_info("my_inh_init = %R\n", (unsigned fract) parameters->my_inh_init); + log_info("my_excitatory_initial_value = %11.4k\n", + parameters->my_input_buffer_excitatory_value); + log_info("my_inhibitory_initial_value = %11.4k\n", + parameters->my_input_buffer_inhibitory_value); +} + +#endif // _SYNAPSE_TYPES_MY_IMPL_H_ diff --git a/neural_modelling/src/meanfield/synapse_types/synapse_types_semd_impl.h b/neural_modelling/src/meanfield/synapse_types/synapse_types_semd_impl.h new file mode 100644 index 00000000000..1360aab1445 --- /dev/null +++ b/neural_modelling/src/meanfield/synapse_types/synapse_types_semd_impl.h @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/*! \file +* +* \brief implementation of synapse_types.h for sEMD synapses. +* +* \details To be filled in... +*/ + +#ifndef _SYNAPSE_TYPES_SEMD_IMPL_H_ +#define _SYNAPSE_TYPES_SEMD_IMPL_H_ + +//--------------------------------------- +// Macros +//--------------------------------------- +//! \brief Number of bits to encode the synapse type +//! \details ceil(log2(#SYNAPSE_TYPE_COUNT)) +#define SYNAPSE_TYPE_BITS 2 +//! \brief Number of synapse types +//! \details #NUM_EXCITATORY_RECEPTORS + #NUM_INHIBITORY_RECEPTORS +#define SYNAPSE_TYPE_COUNT 3 + +//! Number of excitatory receptors +#define NUM_EXCITATORY_RECEPTORS 2 +//! Number of inhibitory receptors +#define NUM_INHIBITORY_RECEPTORS 1 + +#include +#include +#include "synapse_types.h" + +//--------------------------------------- +// Synapse parameters +//--------------------------------------- +typedef struct exp_params_t { + decay_t decay; //!< Decay multiplier per timestep + decay_t init; //!< Initial decay factor + input_t synaptic_input_value; //!< The actual synaptic contribution +} exp_params_t; + +struct synapse_param_t { + exp_params_t exc; //!< First excitatory synaptic input + exp_params_t exc2; //!< Second excitatory synaptic input + exp_params_t inh; //!< Inhibitory synaptic input + //! Output scaling factor derived from first excitatory input + input_t multiplicator; + //! History storage used to reset synaptic state + input_t exc2_old; + //! Scaling factor for the secondary response + input_t scaling_factor; +}; + +//! The supported synapse type indices +typedef enum { + EXCITATORY_ONE, //!< First excitatory synaptic input + EXCITATORY_TWO, //!< Second excitatory synaptic input + INHIBITORY, //!< Inhibitory synaptic input +} synapse_semd_input_buffer_regions; + +//--------------------------------------- +// Synapse shaping inline implementation +//--------------------------------------- + +//! \brief Shapes a single parameter +//! \param[in,out] exp_param: The parameter to shape +static inline void exp_shaping(exp_params_t *exp_param) { + // decay value according to decay constant + exp_param->synaptic_input_value = + decay_s1615(exp_param->synaptic_input_value, exp_param->decay); +} + +//! \brief decays the stuff thats sitting in the input buffers as these have not +//! yet been processed and applied to the neuron. +//! +//! This is to compensate for the valve behaviour of a synapse in biology +//! (spike goes in, synapse opens, then closes slowly) +//! plus the leaky aspect of a neuron. +//! +//! \param[in,out] parameters: the pointer to the parameters to use +static inline void synapse_types_shape_input(synapse_param_t *parameters) { + exp_shaping(¶meters->exc); + exp_shaping(¶meters->exc2); + exp_shaping(¶meters->inh); +} + +//! \brief helper function to add input for a given timer period to a given +//! neuron +//! \param[in,out] parameter: the parameter to update +//! \param[in] input: the input to add. +static inline void add_input_exp(exp_params_t *parameter, input_t input) { + parameter->synaptic_input_value = parameter->synaptic_input_value + + decay_s1615(input, parameter->init); +} + +//! \brief adds the inputs for a give timer period to a given neuron that is +//! being simulated by this model +//! \param[in] synapse_type_index: the type of input that this input is to be +//! considered (aka excitatory or inhibitory etc) +//! \param[in,out] parameter: the pointer to the parameters to use +//! \param[in] input: the input for that given synapse_type. +static inline void synapse_types_add_neuron_input( + index_t synapse_type_index, synapse_param_t *parameter, + input_t input) { + switch (synapse_type_index) { + case EXCITATORY_ONE: + add_input_exp(¶meter->exc, input); + break; + case EXCITATORY_TWO: + add_input_exp(¶meter->exc2, input); + break; + case INHIBITORY: + add_input_exp(¶meter->inh, input); + break; + } +} + +//! \brief extracts the excitatory input buffers from the buffers available +//! for a given parameter set +//! \param[in] parameters: the pointer to the parameters to use +//! \return the excitatory input buffers for a given neuron ID. +static inline input_t *synapse_types_get_excitatory_input( + input_t *excitatory_response, synapse_param_t *parameters) { + if (parameters->exc2.synaptic_input_value >= 0.001 + && parameters->multiplicator == 0 + && parameters->exc2_old == 0) { + parameters->multiplicator = parameters->exc.synaptic_input_value; + } else if (parameters->exc2.synaptic_input_value < 0.001) { + parameters->multiplicator = 0; + } + + parameters->exc2_old = parameters->exc2.synaptic_input_value; + + excitatory_response[0] = 0; + excitatory_response[1] = + parameters->exc2.synaptic_input_value * parameters->multiplicator + * parameters->scaling_factor; + return &excitatory_response[0]; +} + +//! \brief extracts the inhibitory input buffers from the buffers available +//! for a given parameter set +//! \param[in] parameters: the pointer to the parameters to use +//! \return the inhibitory input buffers for a given neuron ID. +static inline input_t *synapse_types_get_inhibitory_input( + input_t *inhibitory_response, synapse_param_t *parameters) { + inhibitory_response[0] = parameters->inh.synaptic_input_value; + return &inhibitory_response[0]; +} + +//! \brief returns a human readable character for the type of synapse. +//! examples would be X = excitatory types, I = inhibitory types etc etc. +//! \param[in] synapse_type_index: the synapse type index +//! (there is a specific index interpretation in each synapse type) +//! \return a human readable character representing the synapse type. +static inline const char *synapse_types_get_type_char( + index_t synapse_type_index) { + switch (synapse_type_index) { + case EXCITATORY_ONE: + return "X1"; + case EXCITATORY_TWO: + return "X2"; + case INHIBITORY: + return "I"; + default: + log_debug("did not recognise synapse type %i", synapse_type_index); + return "?"; + } +} + +//! \brief prints the input for a neuron ID given the available inputs +//! currently only executed when the models are in debug mode, as the prints +//! are controlled from the synapses.c print_inputs() method. +//! \param[in] parameters: the parameters to print +static inline void synapse_types_print_input(synapse_param_t *parameters) { + io_printf(IO_BUF, "%12.6k + %12.6k - %12.6k", + parameters->exc.synaptic_input_value, + parameters->exc2.synaptic_input_value, + parameters->inh.synaptic_input_value); +} + +//! \brief printer call +//! \param[in] parameters: the pointer to the parameters to print +static inline void synapse_types_print_parameters(synapse_param_t *parameters) { + log_info("exc_decay = %11.4k\n", parameters->exc.decay); + log_info("exc_init = %11.4k\n", parameters->exc.init); + log_info("exc2_decay = %11.4k\n", parameters->exc2.decay); + log_info("exc2_init = %11.4k\n", parameters->exc2.init); + log_info("inh_decay = %11.4k\n", parameters->inh.decay); + log_info("inh_init = %11.4k\n", parameters->inh.init); + log_info("gsyn_excitatory_initial_value = %11.4k\n", + parameters->exc.synaptic_input_value); + log_info("gsyn_excitatory2_initial_value = %11.4k\n", + parameters->exc2.synaptic_input_value); + log_info("gsyn_inhibitory_initial_value = %11.4k\n", + parameters->inh.synaptic_input_value); + log_info("multiplicator = %11.4k\n", parameters->multiplicator); + log_info("exc2_old = %11.4k\n", parameters->exc2_old); + log_info("scaling_factor = %11.4k\n", parameters->scaling_factor); +} + +#endif // _SYNAPSE_TYPES_SEMD_IMPL_H_ diff --git a/neural_modelling/src/meanfield/synapses.c b/neural_modelling/src/meanfield/synapses.c new file mode 100644 index 00000000000..2a384fe6384 --- /dev/null +++ b/neural_modelling/src/meanfield/synapses.c @@ -0,0 +1,400 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Implementation of non-inlined API in synapses.h +#include "synapses.h" +#include "spike_processing.h" +#include "meanfield.h" +#include "plasticity/synapse_dynamics.h" +#include +#include +#include +#include + +//! if using profiler import profiler tags +#ifdef PROFILER_ENABLED +#include "profile_tags.h" +#endif //PROFILER_ENABLED + +//! Globals required for synapse benchmarking to work. +uint32_t num_fixed_pre_synaptic_events = 0; + +//! The number of neurons +static uint32_t n_neurons; + +//! The number of synapse types +static uint32_t n_synapse_types; + +//! Ring buffers to handle delays between synapses and neurons +static weight_t *ring_buffers; + +//! Ring buffer size +static uint32_t ring_buffer_size; + +//! Amount to left shift the ring buffer by to make it an input +static uint32_t *ring_buffer_to_input_left_shifts; + +//! \brief Number of bits needed for the synapse type and index +//! \details +//! ``` +//! synapse_index_bits + synapse_type_bits +//! ``` +static uint32_t synapse_type_index_bits; +//! \brief Mask to pick out the synapse type and index. +//! \details +//! ``` +//! synapse_index_mask | synapse_type_mask +//! ``` +static uint32_t synapse_type_index_mask; +//! Number of bits in the synapse index +static uint32_t synapse_index_bits; +//! Mask to pick out the synapse index. +static uint32_t synapse_index_mask; +//! Number of bits in the synapse type +static uint32_t synapse_type_bits; +//! Mask to pick out the synapse type. +static uint32_t synapse_type_mask; + +//! Count of the number of times the ring buffers have saturated +uint32_t synapses_saturation_count = 0; + + +/* PRIVATE FUNCTIONS */ + +#if LOG_LEVEL >= LOG_DEBUG +//! \brief get the synapse type character +//! \param[in] synapse_type: the synapse type +//! \return a single character string describing the synapse type +static inline const char *get_type_char(uint32_t synapse_type) { + return neuron_get_synapse_type_char(synapse_type); +} +#endif // LOG_LEVEL >= LOG_DEBUG + +//! \brief Print a synaptic row. +//! +//! Only does anything when debugging. +//! \param[in] synaptic_row: The synaptic row to print +static inline void print_synaptic_row(synaptic_row_t synaptic_row) { + log_debug("Synaptic row, at address %08x, Num plastic words:%u", + (uint32_t) synaptic_row, synapse_row_plastic_size(synaptic_row)); + if (synaptic_row == NULL) { + return; + } +#if LOG_LEVEL >= LOG_DEBUG + io_printf(IO_BUF, "----------------------------------------\n"); + + // Get details of fixed region + synapse_row_fixed_part_t *fixed_region = + synapse_row_fixed_region(synaptic_row); + address_t fixed_synapses = synapse_row_fixed_weight_controls(fixed_region); + size_t n_fixed_synapses = synapse_row_num_fixed_synapses(fixed_region); + io_printf(IO_BUF, + "Fixed region %u fixed synapses (%u plastic control words):\n", + n_fixed_synapses, synapse_row_num_plastic_controls(fixed_region)); + + for (uint32_t i = 0; i < n_fixed_synapses; i++) { + uint32_t synapse = fixed_synapses[i]; + uint32_t synapse_type = synapse_row_sparse_type( + synapse, synapse_index_bits, synapse_type_mask); + + io_printf(IO_BUF, "%08x [%3d: (w: %5u (=", + synapse, i, synapse_row_sparse_weight(synapse)); + synapses_print_weight(synapse_row_sparse_weight(synapse), + ring_buffer_to_input_left_shifts[synapse_type]); + io_printf(IO_BUF, "nA) d: %2u, %s, n = %3u)] - {%08x %08x}\n", + synapse_row_sparse_delay(synapse, synapse_type_index_bits), + get_type_char(synapse_type), + synapse_row_sparse_index(synapse, synapse_index_mask), + SYNAPSE_DELAY_MASK, synapse_type_index_bits); + } + + // If there's a plastic region + if (synapse_row_plastic_size(synaptic_row) > 0) { + io_printf(IO_BUF, "----------------------------------------\n"); + synapse_row_plastic_data_t *plastic_data = + synapse_row_plastic_region(synaptic_row); + synapse_dynamics_print_plastic_synapses( + plastic_data, fixed_region, ring_buffer_to_input_left_shifts); + } + + io_printf(IO_BUF, "----------------------------------------\n"); +#endif // LOG_LEVEL >= LOG_DEBUG +} + +//! \brief Print the contents of the ring buffers. +//! \details Only does anything when debugging. +//! \param[in] time: The current timestamp +static inline void print_ring_buffers(uint32_t time) { + log_debug("Ring Buffer at %u", time); +#if LOG_LEVEL >= LOG_DEBUG + io_printf(IO_BUF, "----------------------------------------\n"); + for (uint32_t n = 0; n < n_neurons; n++) { + for (uint32_t t = 0; t < n_synapse_types; t++) { + // Determine if this row can be omitted + for (uint32_t d = 0; d < (1 << SYNAPSE_DELAY_BITS); d++) { + if (ring_buffers[synapses_get_ring_buffer_index( + d + time, t, n, synapse_type_index_bits, + synapse_index_bits)] != 0) { + goto doPrint; + } + } + continue; + doPrint: + // Have to print the row + io_printf(IO_BUF, "%3d(%s):", n, get_type_char(t)); + for (uint32_t d = 0; d < (1 << SYNAPSE_DELAY_BITS); d++) { + io_printf(IO_BUF, " "); + uint32_t ring_buffer_index = synapses_get_ring_buffer_index( + d + time, t, n, synapse_type_index_bits, + synapse_index_bits); + synapses_print_weight(ring_buffers[ring_buffer_index], + ring_buffer_to_input_left_shifts[t]); + } + io_printf(IO_BUF, "\n"); + } + } + io_printf(IO_BUF, "----------------------------------------\n"); +#endif // LOG_LEVEL >= LOG_DEBUG +} + +//! \brief Print the neuron inputs. +//! \details Only does anything when debugging. +static inline void print_inputs(void) { +#if LOG_LEVEL >= LOG_DEBUG + log_debug("Inputs"); + neuron_print_inputs(); +#endif // LOG_LEVEL >= LOG_DEBUG +} + + +//! \brief The "inner loop" of the neural simulation. +//! \details Every spike event could cause up to 256 different weights to +//! be put into the ring buffer. +//! \param[in] fixed_region: The fixed region of the synaptic matrix +//! \param[in] time: The current simulation time +static inline void process_fixed_synapses( + synapse_row_fixed_part_t *fixed_region, uint32_t time) { + uint32_t *synaptic_words = synapse_row_fixed_weight_controls(fixed_region); + uint32_t fixed_synapse = synapse_row_num_fixed_synapses(fixed_region); + + num_fixed_pre_synaptic_events += fixed_synapse; + + for (; fixed_synapse > 0; fixed_synapse--) { + // Get the next 32 bit word from the synaptic_row + // (should auto increment pointer in single instruction) + uint32_t synaptic_word = *synaptic_words++; + + // Extract components from this word + uint32_t delay = + synapse_row_sparse_delay(synaptic_word, synapse_type_index_bits); + uint32_t combined_synapse_neuron_index = synapse_row_sparse_type_index( + synaptic_word, synapse_type_index_mask); + uint32_t weight = synapse_row_sparse_weight(synaptic_word); + + // Convert into ring buffer offset + uint32_t ring_buffer_index = synapses_get_ring_buffer_index_combined( + delay + time, combined_synapse_neuron_index, + synapse_type_index_bits); + + // Add weight to current ring buffer value + uint32_t accumulation = ring_buffers[ring_buffer_index] + weight; + + // If 17th bit is set, saturate accumulator at UINT16_MAX (0xFFFF) + // **NOTE** 0x10000 can be expressed as an ARM literal, + // but 0xFFFF cannot. Therefore, we use (0x10000 - 1) + // to obtain this value + uint32_t sat_test = accumulation & 0x10000; + if (sat_test) { + accumulation = sat_test - 1; + synapses_saturation_count++; + } + + // Store saturated value back in ring-buffer + ring_buffers[ring_buffer_index] = accumulation; + } +} + +//! Print output debug data on the synapses +static inline void print_synapse_parameters(void) { +// only if the models are compiled in debug mode will this method contain +// said lines. +#if LOG_LEVEL >= LOG_DEBUG + // again neuron_synapse_shaping_params has moved to implementation + neuron_print_synapse_parameters(); +#endif // LOG_LEVEL >= LOG_DEBUG +} + +/* INTERFACE FUNCTIONS */ +bool synapses_initialise( + address_t synapse_params_address, uint32_t n_neurons_value, + uint32_t n_synapse_types_value, + uint32_t **ring_buffer_to_input_buffer_left_shifts, + bool* clear_input_buffers_of_late_packets_init) { + log_debug("synapses_initialise: starting"); + n_neurons = n_neurons_value; + n_synapse_types = n_synapse_types_value; + + // Set up ring buffer left shifts + ring_buffer_to_input_left_shifts = + spin1_malloc(n_synapse_types * sizeof(uint32_t)); + if (ring_buffer_to_input_left_shifts == NULL) { + log_error("Not enough memory to allocate ring buffer"); + return false; + } + + // read bool flag about dropping packets that arrive too late + *clear_input_buffers_of_late_packets_init = synapse_params_address[0]; + + // shift read by 1 word. + synapse_params_address += 1; + + // read in ring buffer to input left shifts + spin1_memcpy( + ring_buffer_to_input_left_shifts, synapse_params_address, + n_synapse_types * sizeof(uint32_t)); + *ring_buffer_to_input_buffer_left_shifts = + ring_buffer_to_input_left_shifts; + + log_debug("synapses_initialise: completed successfully"); + print_synapse_parameters(); + + uint32_t n_neurons_power_2 = n_neurons; + uint32_t log_n_neurons = 1; + if (n_neurons != 1) { + if (!is_power_of_2(n_neurons)) { + n_neurons_power_2 = next_power_of_2(n_neurons); + } + log_n_neurons = ilog_2(n_neurons_power_2); + } + + uint32_t n_synapse_types_power_2 = n_synapse_types; + if (!is_power_of_2(n_synapse_types)) { + n_synapse_types_power_2 = next_power_of_2(n_synapse_types); + } + uint32_t log_n_synapse_types = ilog_2(n_synapse_types_power_2); + + uint32_t n_ring_buffer_bits = + log_n_neurons + log_n_synapse_types + SYNAPSE_DELAY_BITS; + ring_buffer_size = 1 << (n_ring_buffer_bits); + + ring_buffers = spin1_malloc(ring_buffer_size * sizeof(weight_t)); + if (ring_buffers == NULL) { + log_error("Could not allocate %u entries for ring buffers", + ring_buffer_size); + } + for (uint32_t i = 0; i < ring_buffer_size; i++) { + ring_buffers[i] = 0; + } + + synapse_type_index_bits = log_n_neurons + log_n_synapse_types; + synapse_type_index_mask = (1 << synapse_type_index_bits) - 1; + synapse_index_bits = log_n_neurons; + synapse_index_mask = (1 << synapse_index_bits) - 1; + synapse_type_bits = log_n_synapse_types; + synapse_type_mask = (1 << log_n_synapse_types) - 1; + return true; +} + +void synapses_do_timestep_update(timer_t time) { + print_ring_buffers(time); + + // Transfer the input from the ring buffers into the input buffers + for (uint32_t neuron_index = 0; neuron_index < n_neurons; + neuron_index++) { + // Loop through all synapse types + for (uint32_t synapse_type_index = 0; + synapse_type_index < n_synapse_types; synapse_type_index++) { + // Get index in the ring buffers for the current time slot for + // this synapse type and neuron + uint32_t ring_buffer_index = synapses_get_ring_buffer_index( + time, synapse_type_index, neuron_index, + synapse_type_index_bits, synapse_index_bits); + + // Convert ring-buffer entry to input and add on to correct + // input for this synapse type and neuron + neuron_add_inputs( + synapse_type_index, neuron_index, + synapses_convert_weight_to_input( + ring_buffers[ring_buffer_index], + ring_buffer_to_input_left_shifts[synapse_type_index])); + + // Clear ring buffer + ring_buffers[ring_buffer_index] = 0; + } + } + + print_inputs(); +} + +bool synapses_process_synaptic_row( + uint32_t time, synaptic_row_t row, bool *write_back) { + + // Get address of non-plastic region from row + synapse_row_fixed_part_t *fixed_region = synapse_row_fixed_region(row); + + // **TODO** multiple optimised synaptic row formats + //if (plastic_tag(row) == 0) { + // If this row has a plastic region + if (synapse_row_plastic_size(row) > 0) { + // Get region's address + synapse_row_plastic_data_t *plastic_data = + synapse_row_plastic_region(row); + + // Process any plastic synapses + profiler_write_entry_disable_fiq( + PROFILER_ENTER | PROFILER_PROCESS_PLASTIC_SYNAPSES); + if (!synapse_dynamics_process_plastic_synapses(plastic_data, + fixed_region, ring_buffers, time)) { + return false; + } + profiler_write_entry_disable_fiq( + PROFILER_EXIT | PROFILER_PROCESS_PLASTIC_SYNAPSES); + + // Perform DMA write back + *write_back = true; + } + + // Process any fixed synapses + // **NOTE** this is done after initiating DMA in an attempt + // to hide cost of DMA behind this loop to improve the chance + // that the DMA controller is ready to read next synaptic row afterwards + process_fixed_synapses(fixed_region, time); + //} + return true; +} + +uint32_t synapses_get_pre_synaptic_events(void) { + return (num_fixed_pre_synaptic_events + + synapse_dynamics_get_plastic_pre_synaptic_events()); +} + +void synapses_flush_ring_buffers(void) { + for (uint32_t i = 0; i < ring_buffer_size; i++) { + ring_buffers[i] = 0; + } +} + +//! \brief Clear DTCM used by synapses +//! \return true if successful +bool synapses_shut_down(void) { + sark_free(ring_buffer_to_input_left_shifts); + sark_free(ring_buffers); + num_fixed_pre_synaptic_events = 0; + synapses_saturation_count = 0; + return true; +} diff --git a/neural_modelling/src/meanfield/synapses.h b/neural_modelling/src/meanfield/synapses.h new file mode 100644 index 00000000000..2cfcabfad8e --- /dev/null +++ b/neural_modelling/src/meanfield/synapses.h @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Operations on synapses +#ifndef _SYNAPSES_H_ +#define _SYNAPSES_H_ + +#include +#include "synapse_row.h" +#include "meanfield.h" + +//! Count of the number of times the synapses have saturated their weights. +extern uint32_t synapses_saturation_count; + + +//! \brief Get the index of the ring buffer for a given timestep, synapse type +//! and neuron index +//! \param[in] simulation_timestep: +//! \param[in] synapse_type_index: +//! \param[in] neuron_index: +//! \param[in] synapse_type_index_bits: +//! \param[in] synapse_index_bits: +//! \return Index into the ring buffer +static inline index_t synapses_get_ring_buffer_index( + uint32_t simulation_timestep, uint32_t synapse_type_index, + uint32_t neuron_index, uint32_t synapse_type_index_bits, + uint32_t synapse_index_bits) { + return ((simulation_timestep & SYNAPSE_DELAY_MASK) << synapse_type_index_bits) + | (synapse_type_index << synapse_index_bits) + | neuron_index; +} + +//! \brief Get the index of the ring buffer for a given timestep and combined +//! synapse type and neuron index (as stored in a synapse row) +//! \param[in] simulation_timestep: +//! \param[in] combined_synapse_neuron_index: +//! \param[in] synapse_type_index_bits: +//! \return Index into the ring buffer +static inline index_t synapses_get_ring_buffer_index_combined( + uint32_t simulation_timestep, + uint32_t combined_synapse_neuron_index, + uint32_t synapse_type_index_bits) { + return ((simulation_timestep & SYNAPSE_DELAY_MASK) << synapse_type_index_bits) + | combined_synapse_neuron_index; +} + +//! \brief Converts a weight stored in a synapse row to an input +//! \param[in] weight: the weight to convert in synapse-row form +//! \param[in] left_shift: the shift to use when decoding +//! \return the actual input weight for the model +static inline input_t synapses_convert_weight_to_input( + weight_t weight, uint32_t left_shift) { + union { + int_k_t input_type; + s1615 output_type; + } converter; + + converter.input_type = (int_k_t) (weight) << left_shift; + + return converter.output_type; +} + +//! \brief Print the weight of a synapse +//! \param[in] weight: the weight to print in synapse-row form +//! \param[in] left_shift: the shift to use when decoding +static inline void synapses_print_weight( + weight_t weight, uint32_t left_shift) { + if (weight != 0) { + io_printf(IO_BUF, "%12.6k", + synapses_convert_weight_to_input(weight, left_shift)); + } else { + io_printf(IO_BUF, " "); + } +} + +//! \brief Initialise the synapse processing +//! \param[in] synapse_params_address: Synapse configuration in SDRAM +//! \param[in] n_neurons: Number of neurons to simulate +//! \param[in] n_synapse_types: Number of synapse types +//! \param[out] ring_buffer_to_input_buffer_left_shifts: +//! Array of shifts to use when converting from ring buffer values to input +//! buffer values +//! \return True if successfully initialised. False otherwise. +bool synapses_initialise( + address_t synapse_params_address, + uint32_t n_neurons, uint32_t n_synapse_types, + uint32_t **ring_buffer_to_input_buffer_left_shifts, + bool* clear_input_buffers_of_late_packets_init); + +//! \brief Do all the synapse processing for a timestep. +//! \param[in] time: the current simulation time +void synapses_do_timestep_update(timer_t time); + +//! \brief process a synaptic row +//! \param[in] time: the simulated time +//! \param[in] row: the synaptic row in question +//! \param[out] write_back: whether to write back to SDRAM +//! \return True if successful +bool synapses_process_synaptic_row( + uint32_t time, synaptic_row_t row, bool *write_back); + +//! \brief returns the counters for plastic and fixed pre synaptic events based +//! on (if the model was compiled with SYNAPSE_BENCHMARK parameter) or +//! returns 0 +//! \return the counter for plastic and fixed pre synaptic events or 0 +uint32_t synapses_get_pre_synaptic_events(void); + +//! \brief flush the ring buffers +void synapses_flush_ring_buffers(void); + +//! \brief allows clearing of DTCM used by synapses +//! \return true if successful, false otherwise +bool synapses_shut_down(void); + +#endif // _SYNAPSES_H_ diff --git a/neural_modelling/src/meanfield/threshold_types/my_threshold_type.h b/neural_modelling/src/meanfield/threshold_types/my_threshold_type.h new file mode 100644 index 00000000000..e56db3fdace --- /dev/null +++ b/neural_modelling/src/meanfield/threshold_types/my_threshold_type.h @@ -0,0 +1,23 @@ +#ifndef _MY_THRESHOLD_TYPE_H_ +#define _MY_THRESHOLD_TYPE_H_ + +#include + +typedef struct threshold_type_t { + // TODO: Add any additional parameters here + REAL threshold_value; + REAL my_param; +} threshold_type_t; + +static inline bool threshold_type_is_above_threshold(state_t value, + threshold_type_t *threshold_type) { + + // TODO: Perform the appropriate operations + REAL test_value = value * threshold_type->my_param; + + // TODO: Update to return true or false depending on if the + // threshold has been reached + return REAL_COMPARE(test_value, >=, threshold_type->threshold_value); +} + +#endif // _MY_THRESHOLD_TYPE_H_ diff --git a/neural_modelling/src/meanfield/threshold_types/threshold_type.h b/neural_modelling/src/meanfield/threshold_types/threshold_type.h new file mode 100644 index 00000000000..6fa28a54633 --- /dev/null +++ b/neural_modelling/src/meanfield/threshold_types/threshold_type.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \dir +//! \brief Neuron firing thresholds +//! \file +//! \brief API for threshold types + +#ifndef _THRESHOLD_TYPE_H_ +#define _THRESHOLD_TYPE_H_ + +#include + +// Forward declaration of the threshold pointer type +struct threshold_type_t; +typedef struct threshold_type_t threshold_type_t; +//! Pointer to a threshold type +typedef threshold_type_t* threshold_type_pointer_t; + +//! \brief Determines if the value given is above the threshold value +//! \param[in] value: The value to determine if it is above the threshold +//! \param[in] threshold_type: The parameters to use to determine the result +//! \return True if the neuron should fire +static bool threshold_type_is_above_threshold( + state_t value, threshold_type_t *threshold_type); + +#endif // _THRESHOLD_TYPE_H_ diff --git a/neural_modelling/src/meanfield/threshold_types/threshold_type_maass_stochastic.h b/neural_modelling/src/meanfield/threshold_types/threshold_type_maass_stochastic.h new file mode 100644 index 00000000000..936fa0e7cce --- /dev/null +++ b/neural_modelling/src/meanfield/threshold_types/threshold_type_maass_stochastic.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Stochastic threshold, due to Wolfgang Maass _et al._ +#ifndef _THRESHOLD_TYPE_STOCHASTIC_H_ +#define _THRESHOLD_TYPE_STOCHASTIC_H_ + +#include "threshold_type.h" +#include +#include + +//! Probability of firing when at saturation +#define PROB_SATURATION 0.8k + +//! Stochastic threshold configuration +struct threshold_type_t { + //! sensitivity of soft threshold to membrane voltage [mV-1] + //! (inverted in python code) + REAL du_th_inv; + //! time constant for soft threshold [ms-1] + //! (inverted in python code) + REAL tau_th_inv; + //! soft threshold value [mV] + REAL v_thresh; + //! time step scaling factor + REAL neg_machine_time_step_ms_div_10; +}; + +//! \brief Determines if the value given is above the threshold value +//! \param[in] value: The value to determine if it is above the threshold +//! \param[in] threshold_type: The parameters to use to determine the result +//! \return True if the neuron should fire +static inline bool threshold_type_is_above_threshold( + state_t value, threshold_type_t *threshold_type) { + UREAL random_number = ukbits(mars_kiss64_simp() & 0xFFFF); + + REAL exponent = (value - threshold_type->v_thresh) + * threshold_type->du_th_inv; + + // if exponent is large, further calculation is unnecessary + // (result --> prob_saturation). + UREAL result; + if (exponent < 5.0k) { + REAL hazard = expk(exponent) * threshold_type->tau_th_inv; + result = (1. - expk(hazard * + threshold_type->neg_machine_time_step_ms_div_10)) * + PROB_SATURATION; + } else { + result = PROB_SATURATION; + } + + return REAL_COMPARE(result, >=, random_number); +} + +#endif // _THRESHOLD_TYPE_STOCHASTIC_H_ diff --git a/neural_modelling/src/meanfield/threshold_types/threshold_type_none.h b/neural_modelling/src/meanfield/threshold_types/threshold_type_none.h new file mode 100644 index 00000000000..e525603e052 --- /dev/null +++ b/neural_modelling/src/meanfield/threshold_types/threshold_type_none.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Threshold that never fires +#ifndef _THRESHOLD_TYPE_NONE_H_ +#define _THRESHOLD_TYPE_NONE_H_ + +#include "threshold_type.h" + +struct threshold_type_t { +}; + +//! \brief Determines if the value given is above the threshold value +//! \param[in] value: The value to determine if it is above the threshold +//! \param[in] threshold_type: The parameters to use to determine the result +//! \return True if the neuron should fire +static inline bool threshold_type_is_above_threshold( + UNUSED state_t value, UNUSED threshold_type_t *threshold_type) { + return 0; +} + +#endif // _THRESHOLD_TYPE_NONE_H_ diff --git a/neural_modelling/src/meanfield/threshold_types/threshold_type_static.h b/neural_modelling/src/meanfield/threshold_types/threshold_type_static.h new file mode 100644 index 00000000000..30c9b238f93 --- /dev/null +++ b/neural_modelling/src/meanfield/threshold_types/threshold_type_static.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Threshold that fires at a fixed level +#ifndef _THRESHOLD_TYPE_STATIC_H_ +#define _THRESHOLD_TYPE_STATIC_H_ + +#include "threshold_type.h" + +//! Static threshold configuration +struct threshold_type_t { + //! The value of the static threshold + REAL threshold_value; +}; + +//! \brief Determines if the value given is above the threshold value +//! \param[in] value: The value to determine if it is above the threshold +//! \param[in] threshold_type: The parameters to use to determine the result +//! \return True if the neuron should fire +static inline bool threshold_type_is_above_threshold( + state_t value, threshold_type_t *threshold_type) { + return REAL_COMPARE(value, >=, threshold_type->threshold_value); +} + +#endif // _THRESHOLD_TYPE_STATIC_H_ diff --git a/neural_modelling/src/meanfield_fixing/additional_inputs/additional_input.h b/neural_modelling/src/meanfield_fixing/additional_inputs/additional_input.h new file mode 100644 index 00000000000..f3f376c86c7 --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/additional_inputs/additional_input.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \dir +//! \brief Additional inputs to neuron models +//! \file +//! \brief API for additional inputs +#ifndef _ADDITIONAL_INPUT_TYPE_H_ +#define _ADDITIONAL_INPUT_TYPE_H_ + +#include + +// Forward declaration of the additional input pointer +struct additional_input_t; +typedef struct additional_input_t additional_input_t; +//! Pointer to additional_input_t +typedef additional_input_t *additional_input_pointer_t; + +//! \brief Gets the value of current provided by the additional input this +//! timestep +//! \param[in] additional_input: The additional input type pointer to the +//! parameters +//! \param[in] membrane_voltage: The membrane voltage of the neuron +//! \return The value of the input after scaling +static input_t additional_input_get_input_value_as_current( + struct additional_input_t *additional_input, + state_t membrane_voltage); + +//! \brief Notifies the additional input type that the neuron has spiked +//! \param[in] additional_input: The additional input type pointer to the +//! parameters +static void additional_input_has_spiked( + struct additional_input_t *additional_input); + +#endif // _ADDITIONAL_INPUT_TYPE_H_ diff --git a/neural_modelling/src/meanfield_fixing/additional_inputs/additional_input_none_impl.h b/neural_modelling/src/meanfield_fixing/additional_inputs/additional_input_none_impl.h new file mode 100644 index 00000000000..bb2d71236cc --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/additional_inputs/additional_input_none_impl.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Implementation of "no-such-input" additional input +#ifndef _ADDITIONAL_INPUT_TYPE_NONE_H_ +#define _ADDITIONAL_INPUT_TYPE_NONE_H_ + +#include "additional_input.h" + +//! An empty additional input that makes no contribution +struct additional_input_t { +}; + +//! \brief Gets the value of current provided by the additional input this +//! timestep +//! \details Does nothing +//! \param[in] additional_input: The additional input type pointer to the +//! parameters +//! \param[in] membrane_voltage: The membrane voltage of the neuron +//! \return The value of the input after scaling +static inline input_t additional_input_get_input_value_as_current( + UNUSED struct additional_input_t *additional_input, + UNUSED state_t membrane_voltage) { + return 0; +} + +//! \brief Notifies the additional input type that the neuron has spiked +//! \details Does nothing +//! \param[in] additional_input: The additional input type pointer to the +//! parameters +static inline void additional_input_has_spiked( + UNUSED struct additional_input_t *additional_input) { +} + +#endif // _ADDITIONAL_INPUT_TYPE_NONE_H_ diff --git a/neural_modelling/src/meanfield_fixing/additional_inputs/my_additional_input.h b/neural_modelling/src/meanfield_fixing/additional_inputs/my_additional_input.h new file mode 100644 index 00000000000..48478430d9a --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/additional_inputs/my_additional_input.h @@ -0,0 +1,35 @@ +#ifndef _ADDITIONAL_INPUT_H_ +#define _ADDITIONAL_INPUT_H_ + +#include + +typedef struct additional_input_t { + //REAL my_parameter; + //REAL input_current; +} additional_input_t; + + +//! \brief Gets the value of current provided by the additional input this +//! timestep +//! \param[in] additional_input The additional input type pointer to the +//! parameters +//! \param[in] membrane_voltage The membrane voltage of the neuron +//! \return The value of the input after scaling +static input_t additional_input_get_input_value_as_current( + additional_input_t *additional_input, + state_t membrane_voltage) { + use(membrane_voltage); + additional_input->input_current += additional_input->my_parameter; + return additional_input->input_current; +} + +//! \brief Notifies the additional input type that the neuron has spiked +//! \param[in] additional_input The additional input type pointer to the +//! parameters +static void additional_input_has_spiked( + additional_input_t *additional_input) { + additional_input->input_current = 0; +} + + +#endif // _MY_ADDITIONAL_INPUT_H_ diff --git a/neural_modelling/src/meanfield_fixing/c_main.c b/neural_modelling/src/meanfield_fixing/c_main.c new file mode 100644 index 00000000000..583e90c51c8 --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/c_main.c @@ -0,0 +1,426 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/*! + * @dir + * @brief Implementation of simulator for a single neural population on a + * SpiNNaker CPU core. Or rather of a slice of a population. + * + * @file + * @brief This file contains the main function of the application framework, + * which the application programmer uses to configure and run applications. + * + * This is the main entrance class for most of the neural models. The following + * Figure shows how all of the c code + * interacts with each other and what classes + * are used to represent over arching logic + * (such as plasticity, spike processing, utilities, synapse types, models) + * + * @image html spynnaker_c_code_flow.png + */ + +#include +#include "regions.h" +#include "meanfield.h" +#include "synapses.h" +#include "spike_processing.h" +#include "population_table/population_table.h" +#include "plasticity/synapse_dynamics.h" +#include "structural_plasticity/synaptogenesis_dynamics.h" +#include "profile_tags.h" +#include "direct_synapses.h" + +#include +#include +#include +#include +#include +#include +#include + +/* validates that the model being compiled does indeed contain a application + * magic number*/ +#ifndef APPLICATION_NAME_HASH +#error APPLICATION_NAME_HASH was undefined. Make sure you define this\ + constant +#endif + +//! The provenance information written on application shutdown. +struct neuron_provenance { + //! A count of presynaptic events. + uint32_t n_pre_synaptic_events; + //! A count of synaptic saturations. + uint32_t n_synaptic_weight_saturations; + //! A count of the times that the synaptic input circular buffers overflowed + uint32_t n_input_buffer_overflows; + //! The current time. + uint32_t current_timer_tick; + //! The number of STDP weight saturations. + uint32_t n_plastic_synaptic_weight_saturations; + uint32_t n_ghost_pop_table_searches; + uint32_t n_failed_bitfield_reads; + uint32_t n_dmas_complete; + uint32_t n_spikes_processed; + uint32_t n_invalid_master_pop_table_hits; + uint32_t n_filtered_by_bitfield; + //! The number of rewirings performed. + uint32_t n_rewires; + uint32_t n_packets_dropped_from_lateness; + uint32_t spike_processing_get_max_filled_input_buffer_size; + //! the number of times the TDMA fully missed its slots + uint32_t n_tdma_mises; + //! Maximum backgrounds queued + uint32_t max_backgrounds_queued; + //! Background queue overloads + uint32_t n_background_queue_overloads; +}; + +//! values for the priority for each callback +typedef enum callback_priorities { + MC = -1, DMA = 0, USER = 0, TIMER = 0, SDP = 1, BACKGROUND = 1 +} callback_priorities; + +//! The number of regions that are to be used for recording +#define NUMBER_OF_REGIONS_TO_RECORD 4 + +// Globals + +//! The current timer tick value. +// the timer tick callback returning the same value. +uint32_t time; + +//! timer tick period (in microseconds) +static uint32_t timer_period; + +//! The number of timer ticks to run for before being expected to exit +static uint32_t simulation_ticks = 0; + +//! Determines if this model should run for infinite time +static uint32_t infinite_run; + +//! Timer callbacks since last rewiring +static int32_t last_rewiring_time = 0; + +//! Rewiring period represented as an integer +static int32_t rewiring_period = 0; + +//! Flag representing whether rewiring is enabled +static bool rewiring = false; + +//! Count the number of rewiring attempts +static uint32_t count_rewire_attempts = 0; + +//! The number of neurons on the core +static uint32_t n_neurons; + +//! The number of background tasks queued / running +static uint32_t n_backgrounds_queued = 0; + +//! The number of times the background couldn't be added +static uint32_t n_background_overloads = 0; + +//! The maximum number of background tasks queued +static uint32_t max_backgrounds_queued = 0; + +//! timer count for tdma of certain models; exported +uint global_timer_count; + + +//! \brief Callback to store provenance data (format: neuron_provenance). +//! \param[out] provenance_region: Where to write the provenance data +static void c_main_store_provenance_data(address_t provenance_region) { + log_debug("writing other provenance data"); + struct neuron_provenance *prov = (void *) provenance_region; + + // store the data into the provenance data region + prov->n_pre_synaptic_events = synapses_get_pre_synaptic_events(); + prov->n_synaptic_weight_saturations = synapses_saturation_count; + prov->n_input_buffer_overflows = spike_processing_get_buffer_overflows(); + prov->current_timer_tick = time; + prov->n_plastic_synaptic_weight_saturations = + synapse_dynamics_get_plastic_saturation_count(); + prov->n_ghost_pop_table_searches = ghost_pop_table_searches; + prov->n_failed_bitfield_reads = failed_bit_field_reads; + prov->n_dmas_complete = spike_processing_get_dma_complete_count(); + prov->n_spikes_processed = spike_processing_get_spike_processing_count(); + prov->n_invalid_master_pop_table_hits = invalid_master_pop_hits; + prov->n_filtered_by_bitfield = bit_field_filtered_packets; + prov->n_rewires = spike_processing_get_successful_rewires(); + prov->n_packets_dropped_from_lateness = + spike_processing_get_n_packets_dropped_from_lateness(); + prov->spike_processing_get_max_filled_input_buffer_size = + spike_processing_get_max_filled_input_buffer_size(); + prov->n_tdma_mises = tdma_processing_times_behind(); + prov->n_background_queue_overloads = n_background_overloads; + prov->max_backgrounds_queued = max_backgrounds_queued; + + log_debug("finished other provenance data"); +} + +//! \brief Initialises the model by reading in the regions and checking +//! recording data. +//! \return True if it successfully initialised, false otherwise +static bool initialise(void) { + log_debug("Initialise: started"); + + // Get the address this core's DTCM data starts at from SRAM + data_specification_metadata_t *ds_regions = + data_specification_get_data_address(); + + // Read the header + if (!data_specification_read_header(ds_regions)) { + return false; + } + + // Get the timing details and set up the simulation interface + if (!simulation_initialise( + data_specification_get_region(SYSTEM_REGION, ds_regions), + APPLICATION_NAME_HASH, &timer_period, &simulation_ticks, + &infinite_run, &time, SDP, DMA)) { + return false; + } + simulation_set_provenance_function( + c_main_store_provenance_data, + data_specification_get_region(PROVENANCE_DATA_REGION, ds_regions)); + + // Set up the neurons + uint32_t n_synapse_types; + uint32_t incoming_spike_buffer_size; + uint32_t n_regions_used; + if (!neuron_initialise( + data_specification_get_region(NEURON_PARAMS_REGION, ds_regions), + data_specification_get_region(NEURON_RECORDING_REGION, ds_regions), + &n_neurons, + &n_synapse_types, &incoming_spike_buffer_size, + &n_regions_used)) { + return false; + } + + // Set up the synapses + + uint32_t *ring_buffer_to_input_buffer_left_shifts; + bool clear_input_buffers_of_late_packets_init; + if (!synapses_initialise( + data_specification_get_region(SYNAPSE_PARAMS_REGION, ds_regions), + n_neurons, n_synapse_types, + &ring_buffer_to_input_buffer_left_shifts, + &clear_input_buffers_of_late_packets_init)) { + return false; + } + + + // set up direct synapses + + address_t direct_synapses_address; + if (!direct_synapses_initialise( + data_specification_get_region(DIRECT_MATRIX_REGION, ds_regions), + &direct_synapses_address)) { + return false; + } + + + // Set up the population table + uint32_t row_max_n_words; + if (!population_table_initialise( + data_specification_get_region(POPULATION_TABLE_REGION, ds_regions), + data_specification_get_region(SYNAPTIC_MATRIX_REGION, ds_regions), + direct_synapses_address, + &row_max_n_words)) { + return false; + } + // Set up the synapse dynamics + + if (!synapse_dynamics_initialise( + data_specification_get_region(SYNAPSE_DYNAMICS_REGION, ds_regions), + n_neurons, n_synapse_types, + ring_buffer_to_input_buffer_left_shifts)) { + return false; + } + + + // Set up structural plasticity dynamics + if (!synaptogenesis_dynamics_initialise(data_specification_get_region( + STRUCTURAL_DYNAMICS_REGION, ds_regions))) { + return false; + } + + rewiring_period = synaptogenesis_rewiring_period(); + rewiring = rewiring_period != -1; + + if (!spike_processing_initialise( + row_max_n_words, MC, USER, incoming_spike_buffer_size, + clear_input_buffers_of_late_packets_init, n_regions_used)) { + return false; + } + + + // Setup profiler + profiler_init(data_specification_get_region(PROFILER_REGION, ds_regions)); + + // Do bitfield configuration last to only use any unused memory + if (!population_table_load_bitfields( + data_specification_get_region(BIT_FIELD_FILTER_REGION, ds_regions))) { + return false; + } + + print_post_to_pre_entry(); + + log_debug("Initialise: finished"); + return true; +} + +//! \brief the function to call when resuming a simulation +void resume_callback(void) { + data_specification_metadata_t *ds_regions = + data_specification_get_data_address(); + + //! try resuming neuron + if (!neuron_resume( + data_specification_get_region(NEURON_PARAMS_REGION, ds_regions))) { + log_error("failed to resume neuron."); + rt_error(RTE_SWERR); + } + + // If the time has been reset to zero then the ring buffers need to be + // flushed in case there is a delayed spike left over from a previous run + // NOTE: at reset, time is set to UINT_MAX ahead of timer_callback(...) + if ((time+1) == 0) { + synapses_flush_ring_buffers(); + } + +} + +//! \brief Background activites called from timer +//! \param timer_count the number of times this call back has been +//! executed since start of simulation +//! \param[in] local_time: The time step being executed +void background_callback(uint timer_count, uint local_time) { + global_timer_count = timer_count; + profiler_write_entry_disable_irq_fiq(PROFILER_ENTER | PROFILER_TIMER); + + last_rewiring_time++; + + // This is the part where I save the input and output indices + // from the circular buffer + // If time == 0 as well as output == input == 0 then no rewire is + // supposed to happen. No spikes yet + log_debug("Timer tick %u \n", local_time); + + // Then do rewiring + + if (rewiring && + ((last_rewiring_time >= rewiring_period && !synaptogenesis_is_fast()) + || synaptogenesis_is_fast())) { + last_rewiring_time = 0; + // put flag in spike processing to do synaptic rewiring + if (synaptogenesis_is_fast()) { + spike_processing_do_rewiring(rewiring_period); + } else { + spike_processing_do_rewiring(1); + } + count_rewire_attempts++; + } + + + // Now do neuron time step update + neuron_do_timestep_update(local_time, timer_count); + + profiler_write_entry_disable_irq_fiq(PROFILER_EXIT | PROFILER_TIMER); + n_backgrounds_queued--; +} + +//! \brief Timer interrupt callback +//! \param[in] timer_count: the number of times this call back has been +//! executed since start of simulation +//! \param[in] unused: unused parameter kept for API consistency +void timer_callback(uint timer_count, UNUSED uint unused) { + // Disable interrupts to stop DMAs and MC getting in the way of this bit + uint32_t state = spin1_int_disable(); + + time++; + + // Clear any outstanding spikes + spike_processing_clear_input_buffer(time); + + spin1_mode_restore(state); + state = spin1_irq_disable(); + + // Also do synapses timestep update, as this is time-critical + synapses_do_timestep_update(time); + + /* if a fixed number of simulation ticks that were specified at startup + * then do reporting for finishing */ + if (simulation_is_finished()) { + + // Enter pause and resume state to avoid another tick + simulation_handle_pause_resume(resume_callback); + + log_debug("Completed a run"); + + // rewrite neuron params to SDRAM for reading out if needed + data_specification_metadata_t *ds_regions = + data_specification_get_data_address(); + neuron_pause(data_specification_get_region(NEURON_PARAMS_REGION, ds_regions)); + + profiler_write_entry_disable_irq_fiq(PROFILER_EXIT | PROFILER_TIMER); + + profiler_finalise(); + + // Subtract 1 from the time so this tick gets done again on the next + // run + time--; + + log_debug("Rewire tries = %d", count_rewire_attempts); + simulation_ready_to_read(); + spin1_mode_restore(state); + return; + } + + // Push the rest to the background + if (!spin1_schedule_callback(background_callback, timer_count, time, BACKGROUND)) { + // We have failed to do this timer tick! + n_background_overloads++; + } else { + n_backgrounds_queued++; + if (n_backgrounds_queued > max_backgrounds_queued) { + max_backgrounds_queued++; + } + } + + spin1_mode_restore(state); +} + +//! \brief The entry point for this model. +void c_main(void) { + + // initialise the model + if (!initialise()) { + rt_error(RTE_API); + } + + // Start the time at "-1" so that the first tick will be 0 + time = UINT32_MAX; + + // Set timer tick (in microseconds) + log_debug("setting timer tick callback for %d microseconds", timer_period); + spin1_set_timer_tick(timer_period); + + // Set up the timer tick callback (others are handled elsewhere) + spin1_callback_on(TIMER_TICK, timer_callback, TIMER); + + simulation_run(); +} diff --git a/neural_modelling/src/meanfield_fixing/direct_synapses.c b/neural_modelling/src/meanfield_fixing/direct_synapses.c new file mode 100644 index 00000000000..1f1db85780a --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/direct_synapses.c @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2019-2020 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Implementation of direct_synapses.h +#include +#include +#include + +//! \brief The type of a singleton synaptic row. +//! \details The counts are constant. See ::synapse_row_plastic_part_t and +//! ::synapse_row_fixed_part_t for what this is a packed version of. +typedef struct single_synaptic_row_t { + const uint32_t n_plastic; //!< Number of plastic synapses. Always zero + const uint32_t n_fixed; //!< Number of fixed synapses. Always one + const uint32_t n_plastic_controls; //!< Number of plastic controls. Always zero + uint32_t synapse_datum; //!< The value of the single synapse +} single_synaptic_row_t; + +//! Working buffer for direct synapse access +static single_synaptic_row_t single_fixed_synapse = {0, 1, 0, 0}; + +//! The layout of the direct matrix region +typedef struct { + const uint32_t size; //!< Size of data, _not_ number of elements + const uint32_t data[]; //!< Direct matrix data +} direct_matrix_data_t; + +bool direct_synapses_initialise( + void *direct_matrix_address, address_t *direct_synapses_address) { + direct_matrix_data_t *direct_matrix = direct_matrix_address; + // Work out the positions of the direct and indirect synaptic matrices + // and copy the direct matrix to DTCM + uint32_t direct_matrix_size = direct_matrix->size; + log_info("Direct matrix malloc size is %d", direct_matrix_size); + + if (direct_matrix_size != 0) { + void *dtcm_copy = spin1_malloc(direct_matrix_size); + if (dtcm_copy == NULL) { + log_error("Not enough memory to allocate direct matrix"); + return false; + } + log_debug("Copying %u bytes of direct synapses to 0x%08x", + direct_matrix_size, dtcm_copy); + spin1_memcpy(dtcm_copy, direct_matrix->data, direct_matrix_size); + *direct_synapses_address = dtcm_copy; + } + + return true; +} + +synaptic_row_t direct_synapses_get_direct_synapse(void *row_address) { + uint32_t *data = row_address; + single_fixed_synapse.synapse_datum = *data; + return (synaptic_row_t) &single_fixed_synapse; +} diff --git a/neural_modelling/src/meanfield_fixing/direct_synapses.h b/neural_modelling/src/meanfield_fixing/direct_synapses.h new file mode 100644 index 00000000000..5ed75719933 --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/direct_synapses.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2019-2020 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief API for accessing directly encoded synapses +#ifndef _DIRECT_SYNAPSES_H_ +#define _DIRECT_SYNAPSES_H_ + +//! \brief Setup for the direct synapses. +//! \param[in] direct_matrix_address: +//! the SDRAM base address for the direct matrix +//! \param[out] direct_synapses_address: +//! the DTCM address for the direct matrix +//! \return true if successful, false otherwise. +bool direct_synapses_initialise( + void *direct_matrix_address, address_t *direct_synapses_address); + +//! \brief Get the synapse for a given direct synaptic row. +//! \param[in] row_address: the row address to read. +//! \return the synaptic row synapse data. +synaptic_row_t direct_synapses_get_direct_synapse(void *row_address); + +#endif /* _DIRECT_SYNAPSES_H_ */ diff --git a/neural_modelling/src/meanfield_fixing/implementations/meanfield_impl.h b/neural_modelling/src/meanfield_fixing/implementations/meanfield_impl.h new file mode 100644 index 00000000000..9ccf0945b86 --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/implementations/meanfield_impl.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \dir +//! \brief Neuron implementations +//! \file +//! \brief General API of a neuron implementation +#ifndef _MEANFIELD_IMPL_H_ +#define _MEANFIELD_IMPL_H_ + +#include + +//! \brief Initialise the particular implementation of the data +//! \param[in] n_neurons: The number of neurons +//! \return True if successful +static bool meanfield_impl_initialise(uint32_t n_meanfields); + +//! \brief Add inputs to the neuron +//! \param[in] synapse_type_index: the synapse type (e.g. exc. or inh.) +//! \param[in] neuron_index: the index of the neuron +//! \param[in] weights_this_timestep: weight inputs to be added +static void neuron_impl_add_inputs( + index_t synapse_type_index, index_t meanfield_index, + input_t weights_this_timestep); + +//! \brief Load in the neuron parameters +//! \param[in] address: SDRAM block to read parameters from +//! \param[in] next: Offset of next address in store +//! \param[in] n_neurons: The number of neurons +static void neuron_impl_load_neuron_parameters( + address_t address, uint32_t next, uint32_t n_meanfields); + +//! \brief Do the timestep update for the particular implementation +//! \param[in] neuron_index: The index of the neuron to update +//! \param[in] external_bias: External input to be applied to the neuron +//! \return True if a spike has occurred +static bool neuron_impl_do_timestep_update( + index_t meanfield_index, input_t external_bias); + +//! \brief Stores neuron parameters back into SDRAM +//! \param[out] address: the address in SDRAM to start the store +//! \param[in] next: Offset of next address in store +//! \param[in] n_neurons: The number of neurons +static void neuron_impl_store_neuron_parameters( + address_t address, uint32_t next, uint32_t n_meanfields); + +#if LOG_LEVEL >= LOG_DEBUG +//! \brief Print the inputs to the neurons +//! \param[in] n_neurons: The number of neurons +void neuron_impl_print_inputs(uint32_t n_meanfields); + +//! \brief Print the synapse parameters of the neurons +//! \param[in] n_neurons: The number of neurons +void neuron_impl_print_synapse_parameters(uint32_t n_meanfields); + +//! \brief Get the synapse type character for a synapse type +//! \param[in] synapse_type: The synapse type +//! \return The descriptor character (sometimes two characters) +const char *neuron_impl_get_synapse_type_char(uint32_t synapse_type); +#endif // LOG_LEVEL >= LOG_DEBUG + +#endif // _NEURON_IMPL_H_ diff --git a/neural_modelling/src/meanfield_fixing/implementations/meanfield_impl_standard.h b/neural_modelling/src/meanfield_fixing/implementations/meanfield_impl_standard.h new file mode 100644 index 00000000000..8e7ac507c7e --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/implementations/meanfield_impl_standard.h @@ -0,0 +1,509 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Inlined neuron implementation following standard component model +#ifndef _MEANFIELD_IMPL_STD_H_ +#define _MEANFIELD_IMPL_STD_H_ + +#include "meanfield_impl.h" + +// Includes for model parts used in this implementation +#include +#include +#include + +//#include + +#include + +#include +#include +#include + +//#include + + +//#include +//#include +//#include + +// Further includes +#include + + +//! Indices for recording of words +enum word_recording_indices { + //! V (somatic potential) recording index + V_RECORDING_INDEX = 0, + //! Gsyn_exc (excitatory synaptic conductance/current) recording index + GSYN_EXC_RECORDING_INDEX = 1, + //! Gsyn_inh (excitatory synaptic conductance/current) recording index + GSYN_INH_RECORDING_INDEX = 2, + //! Number of recorded word-sized state variables + N_RECORDED_VARS = 10 +}; + +//! Indices for recording of bitfields +enum bitfield_recording_indices { + //! Spike event recording index + SPIKE_RECORDING_BITFIELD = 0, + //! Number of recorded bitfields + N_BITFIELD_VARS = 1 +}; + +// This import depends on variables defined above +#include + +/*static int azer[] = { + 0x41, + 0x43 + };*/ + + +//! Array of meanfield states -> will be change in futur +static meanfield_t *meanfield_array; + +static config_t *config_array; + +static mathsbox_t *mathsbox_array; + + +//! Input states array +static input_type_t *input_type_array; + +//! Additional input array +static additional_input_t *additional_input_array; + +//! Threshold states array +static threshold_type_t *threshold_type_array; + + +//! Global parameters for the neurons +static global_neuron_params_t *global_parameters; + +//! The synapse shaping parameters +static synapse_param_t *neuron_synapse_shaping_params; + +//! The number of steps to run per timestep +static uint n_steps_per_timestep; + +/* +static inline void test(uint32_t time) { + for (uint32_t i = N_RECORDED_VARS; i > 0; i--) { + if (N_RECORDED_VARS==NULL){ + log_error("fail at %u", time); + } + } +} +*/ + + +#ifndef SOMETIMES_UNUSED +#define SOMETIMES_UNUSED __attribute__((unused)) +#endif // !SOMETIMES_UNUSED + +SOMETIMES_UNUSED // Marked unused as only used sometimes +//! \brief Initialise the particular implementation of the data +//! \param[in] n_neurons: The number of neurons +//! \return True if successful +static bool meanfield_impl_initialise(uint32_t n_meanfields) { + // allocate DTCM for the global parameter details + /*if (sizeof(azer)) { + return true ; + }*/ + + if (sizeof(global_neuron_params_t)) { + global_parameters = spin1_malloc(sizeof(global_neuron_params_t)); + if (global_parameters == NULL) { + log_error("Unable to allocate global neuron parameters" + "- Out of DTCM"); + return false; + } + } + + // Allocate DTCM for neuron array + if (sizeof(meanfield_t)) { + meanfield_array = spin1_malloc(n_meanfields * sizeof(meanfield_t)); + if (meanfield_array == NULL) { + log_error("Unable to allocate meanfield array - Out of DTCM"); + return false; + } + } + + // Allocate DTCM for input type array and copy block of data + if (sizeof(config_t)) { + config_array = spin1_malloc(n_meanfields * sizeof(config_t)); + if (config_array == NULL) { + log_error("Unable to allocate config array - Out of DTCM"); + return false; + } + } + + // Allocate DTCM for input type array and copy block of data + if (sizeof(input_type_t)) { + input_type_array = spin1_malloc(n_meanfields * sizeof(input_type_t)); + if (input_type_array == NULL) { + log_error("Unable to allocate input type array - Out of DTCM"); + return false; + } + } + + // Allocate DTCM for additional input array and copy block of data + if (sizeof(additional_input_t)) { + additional_input_array = + spin1_malloc(n_meanfields * sizeof(additional_input_t)); + if (additional_input_array == NULL) { + log_error("Unable to allocate additional input array" + " - Out of DTCM"); + return false; + } + } + + // Allocate DTCM for threshold type array and copy block of data + if (sizeof(threshold_type_t)) { + threshold_type_array = + spin1_malloc(n_meanfields * sizeof(threshold_type_t)); + if (threshold_type_array == NULL) { + log_error("Unable to allocate threshold type array - Out of DTCM"); + return false; + } + } + + // Allocate DTCM for synapse shaping parameters + if (sizeof(synapse_param_t)) { + neuron_synapse_shaping_params = + spin1_malloc(n_meanfields * sizeof(synapse_param_t)); + if (neuron_synapse_shaping_params == NULL) { + log_error("Unable to allocate synapse parameters array" + " - Out of DTCM"); + return false; + } + } + + return true; +} + +SOMETIMES_UNUSED // Marked unused as only used sometimes +// \brief Will be used for communication btw MFs +//! \brief Add inputs to the neuron +//! \param[in] synapse_type_index: the synapse type (e.g. exc. or inh.) +//! \param[in] neuron_index: the index of the neuron +//! \param[in] weights_this_timestep: weight inputs to be added +static void neuron_impl_add_inputs( + index_t synapse_type_index, + index_t neuron_index, + input_t weights_this_timestep) { + // simple wrapper to synapse type input function + synapse_param_t *parameters = + &neuron_synapse_shaping_params[neuron_index]; + synapse_types_add_neuron_input(synapse_type_index, + parameters, weights_this_timestep); + +} + + +//! \brief The number of _words_ required to hold an object of given size +//! \param[in] size: The size of object +//! \return Number of words needed to hold the object (not bytes!) +static uint32_t n_words_needed(size_t size) { + return (size + (sizeof(uint32_t) - 1)) / sizeof(uint32_t); +} + +SOMETIMES_UNUSED // Marked unused as only used sometimes +//! \brief Load in the neuron parameters +//! \param[in] address: SDRAM block to read parameters from +//! \param[in] next: Offset of next address in store +//! \param[in] n_neurons: number of neurons +static void neuron_impl_load_neuron_parameters( + address_t address, uint32_t next, uint32_t n_meanfields) { + log_debug("reading parameters, next is %u, n_meanfields is %u ", + next, n_meanfields); + + // Read the number of steps per timestep + n_steps_per_timestep = address[next++]; + if (n_steps_per_timestep > 1) { + log_debug("Looping over %u steps each timestep", n_steps_per_timestep); + } else if (n_steps_per_timestep == 0) { + log_error("bad number of steps per timestep: 0"); + rt_error(RTE_SWERR); + } + + if (sizeof(global_neuron_params_t)) { + log_debug("writing neuron global parameters"); + spin1_memcpy(global_parameters, &address[next], + sizeof(global_neuron_params_t)); + next += n_words_needed(sizeof(global_neuron_params_t)); + } + + if (sizeof(meanfield_t)) { + log_debug("reading neuron local parameters"); + spin1_memcpy(meanfield_array, &address[next], + n_meanfields * sizeof(meanfield_t)); + next += n_words_needed(n_meanfields * sizeof(meanfield_t)); + } + + if (sizeof(config_t)) { + log_debug("reading input type parameters"); + spin1_memcpy(config_array, &address[next], + n_meanfields * sizeof(config_t)); + next += n_words_needed(n_meanfields * sizeof(config_t)); + } + + + meanfield_model_set_global_neuron_params(global_parameters); + +#if LOG_LEVEL >= LOG_DEBUG + log_debug("-------------------------------------\n"); + for (index_t n = 0; n < n_meanfields; n++) { + meanfield_model_print_parameters(&meanfield_array[n]); + } + log_debug("-------------------------------------\n"); +#endif // LOG_LEVEL >= LOG_DEBUG +} + +SOMETIMES_UNUSED // Marked unused as only used sometimes +//! \brief Do the timestep update for the particular implementation +//! \param[in] neuron_index: The index of the neuron to update +//! \param[in] external_bias: External input to be applied to the neuron +//! \return True if a spike has occurred +static bool neuron_impl_do_timestep_update(index_t meanfield_index, input_t external_bias){ + // Get the neuron itself + meanfield_t *this_meanfield = &meanfield_array[meanfield_index]; + + // Get the input_type parameters and voltage for this neuron + config_t *config_types = &config_array[meanfield_index]; + + mathsbox_t *mathsbox_types = &mathsbox_array[meanfield_index]; + + // Get the input_type parameters and voltage for this neuron + input_type_t *input_types = &input_type_array[meanfield_index]; + + // Get threshold and additional input parameters for this neuron + threshold_type_t *the_threshold_type = &threshold_type_array[meanfield_index]; + additional_input_t *additional_inputs = + &additional_input_array[meanfield_index]; + synapse_param_t *the_synapse_type = + &neuron_synapse_shaping_params[meanfield_index]; + + + // Store whether the neuron has spiked + bool has_spiked = false; + + // Loop however many times requested; do this in reverse for efficiency, + // and because the index doesn't actually matter + for (uint32_t i_step = n_steps_per_timestep; i_step > 0; i_step--) { + // Get the voltage->firing rate + state_t firing_rate = meanfield_model_get_firing_rate(this_meanfield); + + // Get the exc and inh values from the synapses + input_t exc_values[NUM_EXCITATORY_RECEPTORS]; + input_t *exc_syn_values = + synapse_types_get_excitatory_input(exc_values, the_synapse_type); + input_t inh_values[NUM_INHIBITORY_RECEPTORS]; + input_t *inh_syn_values = + synapse_types_get_inhibitory_input(inh_values, the_synapse_type); + + + // Call functions to obtain exc_input and inh_input + + input_t *exc_input_values = input_type_get_input_value( + exc_syn_values, input_types, NUM_EXCITATORY_RECEPTORS); + input_t *inh_input_values = input_type_get_input_value( + inh_syn_values, input_types, NUM_INHIBITORY_RECEPTORS); + + + // Sum g_syn contributions from all receptors for recording + + REAL total_exc = 0; + REAL total_inh = 0; + + for (int i = 0; i < NUM_EXCITATORY_RECEPTORS; i++) { + total_exc += exc_input_values[i]; + } + for (int i = 0; i < NUM_INHIBITORY_RECEPTORS; i++) { + total_inh += inh_input_values[i]; + } + + + // Do recording if on the first step + if (i_step == n_steps_per_timestep) { + neuron_recording_record_accum( + V_RECORDING_INDEX, meanfield_index, firing_rate); + + neuron_recording_record_accum( + GSYN_EXC_RECORDING_INDEX, meanfield_index, total_exc); + neuron_recording_record_accum( + GSYN_INH_RECORDING_INDEX, meanfield_index, total_inh); + + } + + // Call functions to convert exc_input and inh_input to current + input_type_convert_excitatory_input_to_current( + exc_input_values, input_types, firing_rate); + input_type_convert_inhibitory_input_to_current( + inh_input_values, input_types, firing_rate); + + external_bias += additional_input_get_input_value_as_current( + additional_inputs, firing_rate); + + + // update neuron parameters + state_t result = meanfield_model_state_update( + this_meanfield, config_types, mathsbox_types); + + //reinitialise Fout_th + config_types->Fout_th = 0.0; + + // determine if a spike should occur + + bool spike_now = + threshold_type_is_above_threshold(result, the_threshold_type); + + // If spike occurs, communicate to relevant parts of model + if (spike_now) { + has_spiked = true; + + // Call relevant model-based functions + // Tell the neuron model + neuron_model_has_spiked(this_meanfield); + + // Tell the additional input + additional_input_has_spiked(additional_inputs); + } + + + // Shape the existing input according to the included rule + synapse_types_shape_input(the_synapse_type); + if (config_types->Fout_th==0.0) { + has_spiked = true; + } + } + + + if (has_spiked) { + // Record the spike + neuron_recording_record_bit(SPIKE_RECORDING_BITFIELD, meanfield_index); + } + + +#if LOG_LEVEL >= LOG_DEBUG + meanfield_model_print_state_variables(this_meanfield); +#endif // LOG_LEVEL >= LOG_DEBUG + + // Return the boolean to the model timestep update + //return reinitialisation_Fout; + return has_spiked; +} + +SOMETIMES_UNUSED // Marked unused as only used sometimes +//! \brief Stores neuron parameters back into SDRAM +//! \param[out] address: the address in SDRAM to start the store +//! \param[in] next: Offset of next address in store +//! \param[in] n_neurons: number of neurons +static void neuron_impl_store_neuron_parameters( + address_t address, uint32_t next, uint32_t n_meanfields) { + log_debug("writing parameters"); + + // Skip over the steps per timestep + next += 1; + + if (sizeof(global_neuron_params_t)) { + log_debug("writing neuron global parameters"); + spin1_memcpy(&address[next], global_parameters, + sizeof(global_neuron_params_t)); + next += n_words_needed(sizeof(global_neuron_params_t)); + } + + if (sizeof(meanfield_t)) { + log_debug("writing neuron local parameters"); + spin1_memcpy(&address[next], meanfield_array, + n_meanfields * sizeof(meanfield_t)); + next += n_words_needed(n_meanfields * sizeof(meanfield_t)); + } + + if (sizeof(config_t)) { + log_debug("writing input type parameters"); + spin1_memcpy(&address[next], config_array, + n_meanfields * sizeof(config_t)); + next += n_words_needed(n_meanfields * sizeof(config_t)); + } + +} + +/* +#if LOG_LEVEL >= LOG_DEBUG +//! \brief Print the inputs to the neurons +//! \param[in] n_neurons: The number of neurons +void neuron_impl_print_inputs(uint32_t n_meanfields) { + bool empty = true; + for (index_t i = 0; i < n_meanfields; i++) { + synapse_param_t *params = &neuron_synapse_shaping_params[i]; + empty = empty && (0 == bitsk( + synapse_types_get_excitatory_input(params) + - synapse_types_get_inhibitory_input(params))); + } + + if (!empty) { + log_debug("-------------------------------------\n"); + + for (index_t i = 0; i < n_neurons; i++) { + synapse_param_t *params = &neuron_synapse_shaping_params[i]; + input_t input = synapse_types_get_excitatory_input(params) + - synapse_types_get_inhibitory_input(params); + if (bitsk(input) != 0) { + log_debug("%3u: %12.6k (= ", i, input); + synapse_types_print_input(params); + log_debug(")\n"); + } + } + log_debug("-------------------------------------\n"); + } +} +*/ + + +#if LOG_LEVEL >= LOG_DEBUG +void neuron_impl_print_inputs(uint32_t n_meanfields) { + log_debug("-------------------------------------\n"); + for (index_t i = 0; i < n_meanfields; i++) { + meanfield_t *meanfield = &meanfield_array[i]; + log_debug("inputs: %k %k", meanfield->a, meanfield->b); + } + log_debug("-------------------------------------\n"); +} + + +//! \brief Print the synapse parameters of the neurons +//! \param[in] n_neurons: The number of neurons +void neuron_impl_print_synapse_parameters(uint32_t n_neurons) { + log_debug("-------------------------------------\n"); + for (index_t n = 0; n < n_neurons; n++) { + synapse_types_print_parameters(&neuron_synapse_shaping_params[n]); + } + log_debug("-------------------------------------\n"); +} + +//! \brief Get the synapse type character for a synapse type +//! \param[in] synapse_type: The synapse type +//! \return The descriptor character (sometimes two characters) +const char *neuron_impl_get_synapse_type_char(uint32_t synapse_type) { + return synapse_types_get_type_char(synapse_type); +} +#endif // LOG_LEVEL >= LOG_DEBUG + +#endif // _NEURON_IMPL_STANDARD_H_ diff --git a/neural_modelling/src/meanfield_fixing/implementations/my_full_neuron_impl.h b/neural_modelling/src/meanfield_fixing/implementations/my_full_neuron_impl.h new file mode 100644 index 00000000000..05a16f94f33 --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/implementations/my_full_neuron_impl.h @@ -0,0 +1,116 @@ +#ifndef _MY_FULL_NEURON_IMPL_ +#define _MY_FULL_NEURON_IMPL_ + +// Demonstrating that a "neuron model" can be defined in a different +// way without the use of components for additional input / input / threshold + +#include +#include +#include + +#define V_RECORDING_INDEX 0 +#define N_RECORDED_VARS 1 + +#define SPIKE_RECORDING_BITFIELD 0 +#define N_BITFIELD_VARS 1 + +#include + +//! neuron_impl_t struct +typedef struct neuron_impl_t { + accum inputs[2]; + accum v; + accum threshold; +} neuron_impl_t; + +//! Array of neuron states +static neuron_impl_t *neuron_array; + +__attribute__((unused)) // Marked unused as only used sometimes +static bool neuron_impl_initialise(uint32_t n_neurons) { + // Allocate DTCM for neuron array + if (sizeof(neuron_impl_t) != 0) { + neuron_array = spin1_malloc(n_neurons * sizeof(neuron_impl_t)); + if (neuron_array == NULL) { + log_error("Unable to allocate neuron array - Out of DTCM"); + return false; + } + } + + return true; +} + +__attribute__((unused)) // Marked unused as only used sometimes +static void neuron_impl_load_neuron_parameters( + address_t address, uint32_t next, uint32_t n_neurons) { + // Copy parameters to DTCM from SDRAM + spin1_memcpy(neuron_array, &address[next], + n_neurons * sizeof(neuron_impl_t)); +} + +__attribute__((unused)) // Marked unused as only used sometimes +static void neuron_impl_store_neuron_parameters( + address_t address, uint32_t next, uint32_t n_neurons) { + // Copy parameters to SDRAM from DTCM + spin1_memcpy(&address[next], neuron_array, + n_neurons * sizeof(neuron_impl_t)); +} + +__attribute__((unused)) // Marked unused as only used sometimes +static void neuron_impl_add_inputs( + index_t synapse_type_index, index_t neuron_index, + input_t weights_this_timestep) { + // Get the neuron itself + neuron_impl_t *neuron = &neuron_array[neuron_index]; + + // Do something to store the inputs for the next state update + neuron->inputs[synapse_type_index] += weights_this_timestep; +} + +__attribute__((unused)) // Marked unused as only used sometimes +static bool neuron_impl_do_timestep_update( + index_t neuron_index, input_t external_bias) { + // Get the neuron itself + neuron_impl_t *neuron = &neuron_array[neuron_index]; + + // Store the recorded membrane voltage + neuron_recording_record_accum(V_RECORDING_INDEX, neuron_index, neuron->v); + + // Do something to update the state + neuron->v += external_bias + neuron->inputs[0] - neuron->inputs[1]; + neuron->inputs[0] = 0; + neuron->inputs[1] = 0; + + // Determine if the neuron has spiked + if (neuron->v > neuron->threshold) { + // Reset if spiked + neuron->v = 0k; + neuron_recording_record_bit(SPIKE_RECORDING_BITFIELD, neuron_index); + return true; + } + return false; +} + +#if LOG_LEVEL >= LOG_DEBUG +void neuron_impl_print_inputs(uint32_t n_neurons) { + log_debug("-------------------------------------\n"); + for (index_t i = 0; i < n_neurons; i++) { + neuron_impl_t *neuron = &neuron_array[i]; + log_debug("inputs: %k %k", neuron->inputs[0], neuron->inputs[1]); + } + log_debug("-------------------------------------\n"); +} + +void neuron_impl_print_synapse_parameters(uint32_t n_neurons) { + // there aren't any accessible in this example + use(n_neurons); +} + +const char *neuron_impl_get_synapse_type_char(uint32_t synapse_type) { + use(synapse_type); + return 0; +} +#endif // LOG_LEVEL >= LOG_DEBUG + + +#endif // _MY_FULL_NEURON_IMPL_ diff --git a/neural_modelling/src/meanfield_fixing/implementations/my_neuron_impl_semd.h b/neural_modelling/src/meanfield_fixing/implementations/my_neuron_impl_semd.h new file mode 100644 index 00000000000..f2e354668aa --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/implementations/my_neuron_impl_semd.h @@ -0,0 +1,281 @@ +#ifndef _NEURON_IMPL_SEMD_H_ +#define _NEURON_IMPL_SEMD_H_ + +#include + +// Includes for model parts used in this implementation +#include +#include +#include + +// Further includes +#include + +#define V_RECORDING_INDEX 0 +#define GSYN_EXC_RECORDING_INDEX 1 +#define GSYN_INH_RECORDING_INDEX 2 +#define N_RECORDED_VARS 3 + +#define SPIKE_RECORDING_BITFIELD 0 +#define N_BITFIELD_VARS 1 + +#include + +typedef struct input_type_current_semd_t { + // my_multiplicator + REAL my_multiplicator[NUM_INHIBITORY_RECEPTORS]; + + // previous input value + REAL my_inh_input_previous[NUM_INHIBITORY_RECEPTORS]; +} input_type_current_semd_t; + +#define SCALING_FACTOR 40.0k + +static input_type_current_semd_t *input_type_array; + +//! Array of neuron states +static neuron_pointer_t neuron_array; + +//! Threshold states array +static threshold_type_pointer_t threshold_type_array; + +// The synapse shaping parameters +static synapse_param_t *neuron_synapse_shaping_params; + +// The number of steps per timestep to run over +static uint32_t n_steps_per_timestep; + +__attribute__((unused)) // Marked unused as only used sometimes +static bool neuron_impl_initialise(uint32_t n_neurons) { + // Allocate DTCM for neuron array + neuron_array = spin1_malloc(n_neurons * sizeof(neuron_t)); + if (neuron_array == NULL) { + log_error("Unable to allocate neuron array - Out of DTCM"); + return false; + } + + // Allocate DTCM for input type array and copy block of data + input_type_array = + spin1_malloc(n_neurons * sizeof(input_type_current_semd_t)); + if (input_type_array == NULL) { + log_error("Unable to allocate input type array - Out of DTCM"); + return false; + } + + // Allocate DTCM for threshold type array and copy block of data + threshold_type_array = spin1_malloc(n_neurons * sizeof(threshold_type_t)); + if (threshold_type_array == NULL) { + log_error("Unable to allocate threshold type array - Out of DTCM"); + return false; + } + + // Allocate DTCM for synapse shaping parameters + neuron_synapse_shaping_params = + spin1_malloc(n_neurons * sizeof(synapse_param_t)); + if (neuron_synapse_shaping_params == NULL) { + log_error("Unable to allocate synapse parameters array" + " - Out of DTCM"); + return false; + } + + return true; +} + +__attribute__((unused)) // Marked unused as only used sometimes +static void neuron_impl_add_inputs( + index_t synapse_type_index, index_t neuron_index, + input_t weights_this_timestep) { + // simple wrapper to synapse type input function + synapse_param_t *parameters = &neuron_synapse_shaping_params[neuron_index]; + synapse_types_add_neuron_input(synapse_type_index, + parameters, weights_this_timestep); +} + +__attribute__((unused)) // Marked unused as only used sometimes +static void neuron_impl_load_neuron_parameters( + address_t address, uint32_t next, uint32_t n_neurons) { + log_debug("writing parameters, next is %u, n_neurons is %u ", + next, n_neurons); + n_steps_per_timestep = address[next]; + next += 1; + + log_debug("writing neuron local parameters"); + spin1_memcpy(neuron_array, &address[next], n_neurons * sizeof(neuron_t)); + next += (n_neurons * sizeof(neuron_t)) / 4; + + log_debug("writing input type parameters"); + spin1_memcpy(input_type_array, &address[next], + n_neurons * sizeof(input_type_current_semd_t)); + next += (n_neurons * sizeof(input_type_current_semd_t)) / 4; + + log_debug("writing threshold type parameters"); + spin1_memcpy(threshold_type_array, &address[next], + n_neurons * sizeof(threshold_type_t)); + next += (n_neurons * sizeof(threshold_type_t)) / 4; + + log_debug("writing synapse parameters"); + spin1_memcpy(neuron_synapse_shaping_params, &address[next], + n_neurons * sizeof(synapse_param_t)); +} + +__attribute__((unused)) // Marked unused as only used sometimes +static bool neuron_impl_do_timestep_update(index_t neuron_index, + input_t external_bias) { + // Get the neuron itself + neuron_pointer_t neuron = &neuron_array[neuron_index]; + + // Get the input_type parameters and voltage for this neuron + input_type_current_semd_t *input_type = &input_type_array[neuron_index]; + + // Get threshold synapse parameters for this neuron + threshold_type_pointer_t threshold_type = + &threshold_type_array[neuron_index]; + synapse_param_pointer_t synapse_type = + &neuron_synapse_shaping_params[neuron_index]; + + bool spike = false; + for (uint32_t i = n_steps_per_timestep; i > 0; i--) { + + // Get the voltage + state_t voltage = neuron_model_get_membrane_voltage(neuron); + + // Get the exc and inh values from the synapses + input_t exc_values[NUM_EXCITATORY_RECEPTORS]; + input_t* exc_input_values = + synapse_types_get_excitatory_input(exc_values, synapse_type); + input_t inh_values[NUM_INHIBITORY_RECEPTORS]; + input_t* inh_input_values = + synapse_types_get_inhibitory_input(inh_values, synapse_type); + + // Set the inhibitory my_multiplicator value + for (int i = 0; i < NUM_INHIBITORY_RECEPTORS; i++) { + if ((inh_input_values[i] >= 0.01) && + (input_type->my_multiplicator[i] == 0) && + (input_type->my_inh_input_previous[i] == 0)) { + input_type->my_multiplicator[i] = exc_input_values[i]; + } else if (inh_input_values[i] < 0.01) { + input_type->my_multiplicator[i] = 0; + } + input_type->my_inh_input_previous[i] = inh_input_values[i]; + } + + // Sum g_syn contributions from all receptors for recording + REAL total_exc = 0; + REAL total_inh = 0; + + for (int i = 0; i < NUM_EXCITATORY_RECEPTORS; i++) { + total_exc += exc_input_values[i]; + } + for (int i = 0; i < NUM_INHIBITORY_RECEPTORS; i++) { + total_inh += inh_input_values[i]; + } + + // Do recording if on first step + if (i == n_steps_per_timestep) { + neuron_recording_record_accum(V_RECORDING_INDEX, neuron_index, voltage); + neuron_recording_record_accum(GSYN_EXC_RECORDING_INDEX, neuron_index, total_exc); + neuron_recording_record_accum(GSYN_INH_RECORDING_INDEX, neuron_index, total_inh); + } + + // This changes inhibitory to excitatory input + for (int i = 0; i < NUM_INHIBITORY_RECEPTORS; i++) { + inh_input_values[i] = -inh_input_values[i] * SCALING_FACTOR + * input_type->my_multiplicator[i]; + } + + // update neuron parameters + state_t result = neuron_model_state_update( + NUM_EXCITATORY_RECEPTORS, exc_input_values, + NUM_INHIBITORY_RECEPTORS, inh_input_values, external_bias, neuron); + + // determine if a spike should occur + bool spike_now = threshold_type_is_above_threshold(result, threshold_type); + + // If spike occurs, communicate to relevant parts of model + if (spike_now) { + // Call relevant model-based functions + // Tell the neuron model + spike = true; + neuron_model_has_spiked(neuron); + } + + // Shape the existing input according to the included rule + synapse_types_shape_input(synapse_type); + } + + if (spike) { + neuron_recording_record_bit(SPIKE_RECORDING_BITFIELD, neuron_index); + } + + // Return the boolean to the model timestep update + return spike; +} + +//! \brief stores neuron parameter back into sdram +//! \param[in] address: the address in sdram to start the store +__attribute__((unused)) // Marked unused as only used sometimes +static void neuron_impl_store_neuron_parameters( + address_t address, uint32_t next, uint32_t n_neurons) { + log_debug("writing parameters"); + next += 1; + + log_debug("writing neuron local parameters"); + spin1_memcpy(&address[next], neuron_array, + n_neurons * sizeof(neuron_t)); + next += (n_neurons * sizeof(neuron_t)) / 4; + + log_debug("writing input type parameters"); + spin1_memcpy(&address[next], input_type_array, + n_neurons * sizeof(input_type_current_semd_t)); + next += (n_neurons * sizeof(input_type_current_semd_t)) / 4; + + log_debug("writing threshold type parameters"); + spin1_memcpy(&address[next], threshold_type_array, + n_neurons * sizeof(threshold_type_t)); + next += (n_neurons * sizeof(threshold_type_t)) / 4; + + log_debug("writing synapse parameters"); + spin1_memcpy(&address[next], neuron_synapse_shaping_params, + n_neurons * sizeof(synapse_param_t)); +} + +#if LOG_LEVEL >= LOG_DEBUG +void neuron_impl_print_inputs(uint32_t n_neurons) { + bool empty = true; + for (index_t i = 0; i < n_neurons; i++) { + empty = empty && (0 == bitsk( + synapse_types_get_excitatory_input(&neuron_synapse_shaping_params[i]) + - synapse_types_get_inhibitory_input(&neuron_synapse_shaping_params[i]))); + } + + if (!empty) { + log_debug("-------------------------------------\n"); + + for (index_t i = 0; i < n_neurons; i++) { + input_t input = + synapse_types_get_excitatory_input(&neuron_synapse_shaping_params[i]) + - synapse_types_get_inhibitory_input(&neuron_synapse_shaping_params[i]); + if (bitsk(input) != 0) { + log_debug("%3u: %12.6k (= ", i, input); + synapse_types_print_input(&neuron_synapse_shaping_params[i]); + log_debug(")\n"); + } + } + log_debug("-------------------------------------\n"); + } +} + +void neuron_impl_print_synapse_parameters(uint32_t n_neurons) { + log_debug("-------------------------------------\n"); + for (index_t n = 0; n < n_neurons; n++) { + synapse_types_print_parameters(&neuron_synapse_shaping_params[n]); + } + log_debug("-------------------------------------\n"); +} + +const char *neuron_impl_get_synapse_type_char(uint32_t synapse_type) { + return synapse_types_get_type_char(synapse_type); +} +#endif // LOG_LEVEL >= LOG_DEBUG + +#endif // _NEURON_IMPL_SEMD_H_ diff --git a/neural_modelling/src/meanfield_fixing/input_types/input_type.h b/neural_modelling/src/meanfield_fixing/input_types/input_type.h new file mode 100644 index 00000000000..7012f8e8557 --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/input_types/input_type.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \dir +//! \brief Synaptic inputs +//! \file +//! \brief API for synaptic inputs (see also \ref src/neuron/synapse_types) +#ifndef _INPUT_TYPE_H_ +#define _INPUT_TYPE_H_ + +#ifndef NUM_EXCITATORY_RECEPTORS +//! \private +//! \brief The number of excitatory receptors. +//! \details It should be defined by a synapse shaping include. +#define NUM_EXCITATORY_RECEPTORS 1 +#error NUM_EXCITATORY_RECEPTORS was undefined. It should be defined by a synapse\ + shaping include +#endif + +#ifndef NUM_INHIBITORY_RECEPTORS +//! \private +//! \brief The number of inhibitory receptors. +//! \details It should be defined by a synapse shaping include. +#define NUM_INHIBITORY_RECEPTORS 1 +#error NUM_INHIBITORY_RECEPTORS was undefined. It should be defined by a synapse\ + shaping include +#endif + +#include + +// Forward declaration of the input type structure +struct input_type_t; +typedef struct input_type_t input_type_t; +//! Declaration of the input type pointer +typedef input_type_t *input_type_pointer_t; + +//! \brief Gets the actual input value. This allows any scaling to take place +//! \param[in,out] value: The array of the receptor-based values of the input +//! before scaling +//! \param[in] input_type: The input type pointer to the parameters +//! \param[in] num_receptors: The number of receptors. +//! The size of the \p value array. +//! \return Pointer to array of values of the receptor-based input after +//! scaling +static input_t *input_type_get_input_value( + input_t *restrict value, input_type_t *input_type, + uint16_t num_receptors); + +//! \brief Converts an excitatory input into an excitatory current +//! \param[in,out] exc_input: Pointer to array of excitatory inputs from +//! different receptors this timestep. Note that this will already have +//! been scaled by input_type_get_input_value() +//! \param[in] input_type: The input type pointer to the parameters +//! \param[in] membrane_voltage: The membrane voltage to use for the input +static void input_type_convert_excitatory_input_to_current( + input_t *restrict exc_input, const input_type_t *input_type, + state_t membrane_voltage); + +//! \brief Converts an inhibitory input into an inhibitory current +//! \param[in,out] inh_input: Pointer to array of inhibitory inputs from +//! different receptors this timestep. Note that this will already have +//! been scaled by input_type_get_input_value() +//! \param[in] input_type: The input type pointer to the parameters +//! \param[in] membrane_voltage: The membrane voltage to use for the input +static void input_type_convert_inhibitory_input_to_current( + input_t *restrict inh_input, const input_type_t *input_type, + state_t membrane_voltage); + +#endif // _INPUT_TYPE_H_ diff --git a/neural_modelling/src/meanfield_fixing/input_types/input_type_conductance.h b/neural_modelling/src/meanfield_fixing/input_types/input_type_conductance.h new file mode 100644 index 00000000000..d11a37ea3de --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/input_types/input_type_conductance.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Input type is standard conductance-based model +#ifndef _INPUT_TYPE_CONDUCTANCE_H_ +#define _INPUT_TYPE_CONDUCTANCE_H_ + +#include "input_type.h" + +//! Conductance input parameters +typedef struct input_type_t { + //! reversal voltage - Excitatory [mV] + REAL V_rev_E; + //! reversal voltage - Inhibitory [mV] + REAL V_rev_I; +} input_type_t; + +//! \brief Gets the actual input value. This allows any scaling to take place +//! \param[in,out] value: The array of the receptor-based values of the input +//! before scaling +//! \param[in] input_type: The input type pointer to the parameters +//! \param[in] num_receptors: The number of receptors. +//! The size of the \p value array. +//! \return Pointer to array of values of the receptor-based input after +//! scaling +static inline input_t *input_type_get_input_value( + input_t *restrict value, UNUSED input_type_t *input_type, + uint16_t num_receptors) { + for (int i = 0; i < num_receptors; i++) { + value[i] = value[i] >> 10; + } + return &value[0]; +} + +//! \brief Converts an excitatory input into an excitatory current +//! \param[in,out] exc_input: Pointer to array of excitatory inputs from +//! different receptors this timestep. Note that this will already have +//! been scaled by input_type_get_input_value() +//! \param[in] input_type: The input type pointer to the parameters +//! \param[in] membrane_voltage: The membrane voltage to use for the input +static inline void input_type_convert_excitatory_input_to_current( + input_t *restrict exc_input, const input_type_t *input_type, + state_t membrane_voltage) { + for (int i=0; i < NUM_EXCITATORY_RECEPTORS; i++) { + exc_input[i] = exc_input[i] * + (input_type->V_rev_E - membrane_voltage); + } +} + +//! \brief Converts an inhibitory input into an inhibitory current +//! \param[in,out] inh_input: Pointer to array of inhibitory inputs from +//! different receptors this timestep. Note that this will already have +//! been scaled by input_type_get_input_value() +//! \param[in] input_type: The input type pointer to the parameters +//! \param[in] membrane_voltage: The membrane voltage to use for the input +static inline void input_type_convert_inhibitory_input_to_current( + input_t *restrict inh_input, const input_type_t *input_type, + state_t membrane_voltage) { + for (int i=0; i < NUM_INHIBITORY_RECEPTORS; i++) { + inh_input[i] = -inh_input[i] * + (input_type->V_rev_I - membrane_voltage); + } +} + +#endif // _INPUT_TYPE_CONDUCTANCE_H_ diff --git a/neural_modelling/src/meanfield_fixing/input_types/input_type_current.h b/neural_modelling/src/meanfield_fixing/input_types/input_type_current.h new file mode 100644 index 00000000000..3a2843175c5 --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/input_types/input_type_current.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Input type is standard current-based model +#ifndef _INPUT_TYPE_CURRENT_H_ +#define _INPUT_TYPE_CURRENT_H_ + +#include "input_type.h" + +typedef struct input_type_t { +} input_type_t; + +//! Scaling factor (trivial!) for input currents +static const REAL INPUT_SCALE_FACTOR = ONE; + +//! \brief Gets the actual input value. This allows any scaling to take place +//! \param[in,out] value: The array of the receptor-based values of the input +//! before scaling +//! \param[in] input_type: The input type pointer to the parameters +//! \param[in] num_receptors: The number of receptors. +//! The size of the \p value array. +//! \return Pointer to array of values of the receptor-based input after +//! scaling +static inline input_t *input_type_get_input_value( + input_t *restrict value, UNUSED input_type_t *input_type, + uint16_t num_receptors) { + for (int i = 0; i < num_receptors; i++) { + value[i] = value[i] * INPUT_SCALE_FACTOR; + // NOTE: this will be edited in future to be + // multiplied by a real scaling factor + } + return &value[0]; +} + +//! \brief Converts an excitatory input into an excitatory current +//! \param[in,out] exc_input: Pointer to array of excitatory inputs from +//! different receptors this timestep. Note that this will already have +//! been scaled by input_type_get_input_value() +//! \param[in] input_type: The input type pointer to the parameters +//! \param[in] membrane_voltage: The membrane voltage to use for the input +static inline void input_type_convert_excitatory_input_to_current( + UNUSED input_t *restrict exc_input, + UNUSED const input_type_t *input_type, + UNUSED state_t membrane_voltage) { +} + +//! \brief Converts an inhibitory input into an inhibitory current +//! \param[in,out] inh_input: Pointer to array of inhibitory inputs from +//! different receptors this timestep. Note that this will already have +//! been scaled by input_type_get_input_value() +//! \param[in] input_type: The input type pointer to the parameters +//! \param[in] membrane_voltage: The membrane voltage to use for the input +static inline void input_type_convert_inhibitory_input_to_current( + UNUSED input_t *restrict inh_input, + UNUSED const input_type_t *input_type, + UNUSED state_t membrane_voltage) { +} + +#endif // _INPUT_TYPE_CURRENT_H_ diff --git a/neural_modelling/src/meanfield_fixing/input_types/input_type_delta.h b/neural_modelling/src/meanfield_fixing/input_types/input_type_delta.h new file mode 100644 index 00000000000..4dda931f67f --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/input_types/input_type_delta.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Input type shaped as Dirac delta +#ifndef _INPUT_TYPE_DELTA_H_ +#define _INPUT_TYPE_DELTA_H_ + +#include "input_type.h" + +struct input_type_t { + // scale factor (1000.0 / timestep) + REAL scale_factor; +}; + +//! Scaling factor (trivial!) for input currents +static const REAL INPUT_SCALE_FACTOR = ONE; + +//! \brief Gets the actual input value. This allows any scaling to take place +//! \param[in,out] value: The array of the receptor-based values of the input +//! before scaling +//! \param[in] input_type: The input type pointer to the parameters +//! \param[in] num_receptors: The number of receptors. +//! The size of the \p value array. +//! \return Pointer to array of values of the receptor-based input after +//! scaling +static inline input_t *input_type_get_input_value( + input_t *restrict value, UNUSED input_type_t *input_type, + uint16_t num_receptors) { + for (int i = 0; i < num_receptors; i++) { + value[i] = value[i] * INPUT_SCALE_FACTOR; + } + return &value[0]; +} + +//! \brief Converts an excitatory input into an excitatory current +//! \param[in,out] exc_input: Pointer to array of excitatory inputs from +//! different receptors this timestep. Note that this will already have +//! been scaled by input_type_get_input_value() +//! \param[in] input_type: The input type pointer to the parameters +//! \param[in] membrane_voltage: The membrane voltage to use for the input +static inline void input_type_convert_excitatory_input_to_current( + input_t *restrict exc_input, const input_type_t *input_type, + UNUSED state_t membrane_voltage) { + for (int i=0; i < NUM_EXCITATORY_RECEPTORS; i++) { + exc_input[i] = exc_input[i] * input_type->scale_factor; + } +} + +//! \brief Converts an inhibitory input into an inhibitory current +//! \param[in,out] inh_input: Pointer to array of inhibitory inputs from +//! different receptors this timestep. Note that this will already have +//! been scaled by input_type_get_input_value() +//! \param[in] input_type: The input type pointer to the parameters +//! \param[in] membrane_voltage: The membrane voltage to use for the input +static inline void input_type_convert_inhibitory_input_to_current( + input_t *restrict inh_input, const input_type_t *input_type, + UNUSED state_t membrane_voltage) { + for (int i=0; i < NUM_INHIBITORY_RECEPTORS; i++) { + inh_input[i] = inh_input[i] * input_type->scale_factor; + } +} + +#endif // _INPUT_TYPE_DELTA_H_ diff --git a/neural_modelling/src/meanfield_fixing/input_types/input_type_none.h b/neural_modelling/src/meanfield_fixing/input_types/input_type_none.h new file mode 100644 index 00000000000..398fcf395bd --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/input_types/input_type_none.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief The no-input input type +#ifndef _INPUT_TYPE_NONE_H_ +#define _INPUT_TYPE_NONE_H_ + +#ifndef NUM_EXCITATORY_RECEPTORS +//! No inputs, so no receptors +#define NUM_EXCITATORY_RECEPTORS 0 +#endif +#ifndef NUM_INHIBITORY_RECEPTORS +//! No inputs, so no receptors +#define NUM_INHIBITORY_RECEPTORS 0 +#endif + +#include "input_type.h" + +struct input_type_t { +}; + +//! \brief Gets the actual input value. This allows any scaling to take place +//! \details Actually does nothing; no receptors +//! \param[in,out] value: The array of the receptor-based values of the input +//! before scaling +//! \param[in] input_type: The input type pointer to the parameters +//! \param[in] num_receptors: The number of receptors. +//! The size of the \p value array. +//! \return Pointer to array of values of the receptor-based input after +//! scaling +static inline input_t *input_type_get_input_value( + UNUSED input_t *restrict value, UNUSED input_type_t *input_type, + UNUSED uint16_t num_receptors) { + return 0; +} + +//! \brief Converts an excitatory input into an excitatory current +//! \details Actually does nothing; no receptors +//! \param[in,out] exc_input: Pointer to array of excitatory inputs from +//! different receptors this timestep. Note that this will already have +//! been scaled by input_type_get_input_value() +//! \param[in] input_type: The input type pointer to the parameters +//! \param[in] membrane_voltage: The membrane voltage to use for the input +static inline void input_type_convert_excitatory_input_to_current( + UNUSED input_t *restrict exc_input, + UNUSED const input_type_t *input_type, + UNUSED state_t membrane_voltage) { +} + +//! \brief Converts an inhibitory input into an inhibitory current +//! \details Actually does nothing; no receptors +//! \param[in,out] inh_input: Pointer to array of inhibitory inputs from +//! different receptors this timestep. Note that this will already have +//! been scaled by input_type_get_input_value() +//! \param[in] input_type: The input type pointer to the parameters +//! \param[in] membrane_voltage: The membrane voltage to use for the input +static inline void input_type_convert_inhibitory_input_to_current( + UNUSED input_t *restrict inh_input, + UNUSED const input_type_t *input_type, + UNUSED state_t membrane_voltage) { +} + +#endif // _INPUT_TYPE_NONE_H_ diff --git a/neural_modelling/src/meanfield_fixing/input_types/my_input_type.h b/neural_modelling/src/meanfield_fixing/input_types/my_input_type.h new file mode 100644 index 00000000000..05cfdc2fd5d --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/input_types/my_input_type.h @@ -0,0 +1,65 @@ +#ifndef _MY_INPUT_TYPE_H_ +#define _MY_INPUT_TYPE_H_ + +#ifndef NUM_EXCITATORY_RECEPTORS +#define NUM_EXCITATORY_RECEPTORS 1 +#error NUM_EXCITATORY_RECEPTORS was undefined. It should be defined by a synapse\ + shaping include +#endif + +#ifndef NUM_INHIBITORY_RECEPTORS +#define NUM_INHIBITORY_RECEPTORS 1 +#error NUM_INHIBITORY_RECEPTORS was undefined. It should be defined by a synapse\ + shaping include +#endif + +#include + +typedef struct input_type_t { + REAL multiplicator; + REAL my_parameter; +} input_type_t; + +static inline void _input_type_set_multiplicator_value( + input_t total, input_type_t *input_type) { + if (total > input_type->my_parameter) { + input_type->multiplicator = 1.0; + } else { + input_type->multiplicator += 1.0; + } +} + +static inline input_t *input_type_get_input_value( + input_t *restrict value, input_type_t *input_type, + uint16_t num_receptors) { + input_t total = 0.0; + for (uint32_t i = 0; i < num_receptors; i++) { + total += value[i]; + } + + _input_type_set_multiplicator_value(total, input_type); + + return &value[0]; +} + +static inline void input_type_convert_excitatory_input_to_current( + input_t *restrict exc_input, const input_type_t *input_type, + state_t membrane_voltage) { + use(membrane_voltage); + + for (uint32_t i=0; i < NUM_EXCITATORY_RECEPTORS; i++) { + exc_input[i] = exc_input[i] * input_type->multiplicator; + } +} + +static inline void input_type_convert_inhibitory_input_to_current( + input_t *restrict inh_input, const input_type_t *input_type, + state_t membrane_voltage) { + use(membrane_voltage); + + for (uint32_t i=0; i < NUM_INHIBITORY_RECEPTORS; i++) { + inh_input[i] = inh_input[i] * input_type->multiplicator; + } +} + +#endif // _MY_INPUT_TYPE_H_ diff --git a/neural_modelling/src/meanfield_fixing/meanfield.c b/neural_modelling/src/meanfield_fixing/meanfield.c new file mode 100644 index 00000000000..03640a49218 --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/meanfield.c @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/*! \file + * \brief implementation of the meanfield.h interface. + * come from neuron.h + * will change neuron for meanfield but for now need to see if it's work so + no change just necessary + * remove spikes and synapse because MF not need this. + * Will implemente synapse like connection btw MFs after 1MF will work + */ + +#include "meanfield.h" +//#include "implementations/meanfield_impl_standard.h" +#include "meanfield_recording.h" + +#include "implementations/meanfield_impl.h" + +#include "plasticity/synapse_dynamics.h" +#include +#include + +//! The key to be used for this core (will be ORed with neuron ID) +static key_t key; + +//! A checker that says if this model should be transmitting. If set to false +//! by the data region, then this model should not have a key. +static bool use_key; + +//! The number of neurons on the core +static uint32_t n_neurons; + +//! The recording flags +static uint32_t recording_flags = 0; + +//! parameters that reside in the neuron_parameter_data_region +struct neuron_parameters { + uint32_t has_key; + uint32_t transmission_key; + uint32_t n_neurons_to_simulate; + uint32_t n_synapse_types; + uint32_t incoming_spike_buffer_size; +}; + +//! Offset of start of global parameters, in words. +#define START_OF_GLOBAL_PARAMETERS \ + ((sizeof(struct neuron_parameters) + \ + sizeof(struct tdma_parameters)) / sizeof(uint32_t)) + +//! \brief does the memory copy for the neuron parameters +//! \param[in] address: the address where the neuron parameters are stored +//! in SDRAM +//! \return bool which is true if the mem copy's worked, false otherwise +static bool neuron_load_neuron_parameters(address_t address) { + log_debug("loading parameters"); + // call the neuron implementation functions to do the work + neuron_impl_load_neuron_parameters( + address, START_OF_GLOBAL_PARAMETERS, n_neurons); + return true; +} + +bool neuron_resume(address_t address) { // EXPORTED + if (!neuron_recording_reset(n_neurons)){ + log_error("failed to reload the neuron recording parameters"); + return false; + } + + log_debug("neuron_reloading_neuron_parameters: starting"); + return neuron_load_neuron_parameters(address); +} + +bool neuron_initialise( + address_t address, address_t recording_address, // EXPORTED + uint32_t *n_neurons_value, + uint32_t *n_synapse_types_value, + uint32_t *incoming_spike_buffer_size, + uint32_t *n_rec_regions_used) { + log_debug("neuron_initialise: starting"); + + /*static inline void test(uint32_t time) { + for (uint32_t i = N_RECORDED_VARS; i > 0; i--) { + if (N_RECORDED_VARS==NULL){ + log_error("fail at %u", n_neurons_value); + } + } + }*/ + + // init the TDMA + void *data_addr = address; + tdma_processing_initialise(&data_addr); + + // cast left over SDRAM into neuron struct. + struct neuron_parameters *params = data_addr; + + // Check if there is a key to use + use_key = params->has_key; + + // Read the spike key to use + key = params->transmission_key; + + // output if this model is expecting to transmit + if (!use_key) { + log_debug("\tThis model is not expecting to transmit as it has no key"); + } else { + log_debug("\tThis model is expected to transmit with key = %08x", key); + } + + // Read the neuron details + n_neurons = params->n_neurons_to_simulate; + *n_neurons_value = n_neurons; + *n_synapse_types_value = params->n_synapse_types; + + // Read the size of the incoming spike buffer to use + *incoming_spike_buffer_size = params->incoming_spike_buffer_size; + + log_debug("\t n_neurons = %u, spike buffer size = %u", n_neurons, + *incoming_spike_buffer_size); + + // Call the neuron implementation initialise function to setup DTCM etc. + if (!meanfield_impl_initialise(n_neurons)) { + return false; + } + + // load the data into the allocated DTCM spaces. + if (!neuron_load_neuron_parameters(address)) { + return false; + } + + // setup recording region + if (!neuron_recording_initialise( + recording_address, &recording_flags, n_neurons, n_rec_regions_used)) { + return false; + } + + return true; +} + +void neuron_pause(address_t address) { // EXPORTED + /* Finalise any recordings that are in progress, writing back the final + * amounts of samples recorded to SDRAM */ + if (recording_flags > 0) { + log_debug("updating recording regions"); + neuron_recording_finalise(); + } + + // call neuron implementation function to do the work + neuron_impl_store_neuron_parameters( + address, START_OF_GLOBAL_PARAMETERS, n_neurons); +} + +void neuron_do_timestep_update(timer_t time, uint timer_count) { // EXPORTED + + // the phase in this timer tick im in (not tied to neuron index) + tdma_processing_reset_phase(); + + // Prepare recording for the next timestep + neuron_recording_setup_for_next_recording(); + + // update each neuron individually + for (index_t neuron_index = 0; neuron_index < n_neurons; neuron_index++) { + + // Get external bias from any source of intrinsic plasticity + input_t external_bias = + synapse_dynamics_get_intrinsic_bias(time, neuron_index); + + // call the implementation function (boolean for spike) + bool spike = neuron_impl_do_timestep_update( + neuron_index, external_bias); + + // If the neuron has spiked + if (spike) { + log_debug("meanfield %u reinit at time %u", neuron_index, time); + + // Do any required synapse processing + synapse_dynamics_process_post_synaptic_event(time, neuron_index); + + if (use_key) { + tdma_processing_send_packet( + (key | neuron_index), 0, NO_PAYLOAD, timer_count); + } + } else { + log_debug("the neuron %d has been determined to not reinit", + neuron_index); + } + } + + log_debug("time left of the timer after tdma is %d", tc[T1_COUNT]); + + // Disable interrupts to avoid possible concurrent access + uint cpsr = spin1_int_disable(); + + // Record the recorded variables + neuron_recording_record(time); + + // Re-enable interrupts + spin1_mode_restore(cpsr); +} + +void neuron_add_inputs( // EXPORTED + index_t synapse_type_index, + index_t neuron_index, + input_t weights_this_timestep) { + neuron_impl_add_inputs(synapse_type_index, + neuron_index, weights_this_timestep); +} + +#if LOG_LEVEL >= LOG_DEBUG +void neuron_print_inputs(void) { // EXPORTED + neuron_impl_print_inputs(n_neurons); +} + +void neuron_print_synapse_parameters(void) { // EXPORTED + neuron_impl_print_synapse_parameters(n_neurons); +} + +const char *neuron_get_synapse_type_char(uint32_t synapse_type){//EXPORTED + return neuron_impl_get_synapse_type_char(synapse_type); +} +#endif // LOG_LEVEL >= LOG_DEBUG diff --git a/neural_modelling/src/meanfield_fixing/meanfield.h b/neural_modelling/src/meanfield_fixing/meanfield.h new file mode 100644 index 00000000000..a9b5e202681 --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/meanfield.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/*! \file + * \brief interface for neurons + * + * The API contains: + * - neuron_initialise(): + * translate the data stored in the NEURON_PARAMS data region in SDRAM + * and converts it into C-based objects for use. + * - neuron_set_input_buffers(input_buffers_value): + * setter for the internal input buffers + * - neuron_do_timestep_update(): + * executes all the updates to neural parameters when a given timer + * period has occurred. + */ + +#ifndef _MEANFIELD_H_ +#define _MEANFIELD_H_ + +#include +#include + +//! \brief translate the data stored in the NEURON_PARAMS data region in SDRAM +//! and convert it into c based objects for use. +//! \param[in] address: the absolute address in SDRAM for the start of the +//! NEURON_PARAMS data region in SDRAM +//! \param[in] recording_address: the recording parameters in SDRAM +//! (contains which regions are active and how big they are) +//! \param[out] n_neurons_value: The number of neurons this model is to +//! simulate +//! \param[out] n_synapse_types_value: The number of synapse types in +//! the model +//! \param[out] incoming_spike_buffer_size: The number of spikes to +//! support in the incoming spike circular buffer +//! \param[out] n_rec_regions_used: The number of regions used by neuron recording +//! \return True if the translation was successful, otherwise False +bool neuron_initialise( + address_t address, address_t recording_address, uint32_t *n_neurons_value, + uint32_t *n_synapse_types_value, uint32_t *incoming_spike_buffer_size, + uint32_t *n_rec_regions_used); + +//! \brief executes all the updates to neural parameters when a given timer +//! period has occurred. +//! \param[in] time: the timer tick value currently being executed +//! \param[in] timer_count: used for detecting a wrapping timer +void neuron_do_timestep_update(timer_t time, uint timer_count); + +//! \brief Prepare to resume simulation of the neurons +//! \param[in] address: the address where the neuron parameters are stored +//! in SDRAM +//! \return bool which is true if the resume was successful or not +bool neuron_resume(address_t address); + +//! \brief Perform steps needed before pausing a simulation. +//! \details Stores neuron parameters back into SDRAM. +//! \param[in] address: the address where the neuron parameters are stored +//! in SDRAM +void neuron_pause(address_t address); + +//! \brief Add inputs to the neuron +//! \param[in] synapse_type_index the synapse type (e.g. exc. or inh.) +//! \param[in] neuron_index the index of the neuron +//! \param[in] weights_this_timestep weight inputs to be added +void neuron_add_inputs( + index_t synapse_type_index, index_t neuron_index, + input_t weights_this_timestep); + +#if LOG_LEVEL >= LOG_DEBUG +//! \brief Print the inputs to the neurons. +//! \details Only available in debug mode. +void neuron_print_inputs(void); + +//! \brief Print the neurons' synapse parameters. +//! \details Only available in debug mode. +void neuron_print_synapse_parameters(void); + +//! \brief Get the synapse _type_ description character. +//! \details Only available in debug mode. +//! \param[in] synapse_type: The synapse type. +//! \return a single character that describes the synapse. +const char *neuron_get_synapse_type_char(uint32_t synapse_type); +#endif + +#endif // _NEURON_H_ diff --git a/neural_modelling/src/meanfield_fixing/meanfield_recording.c b/neural_modelling/src/meanfield_fixing/meanfield_recording.c new file mode 100644 index 00000000000..cae80a334cd --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/meanfield_recording.c @@ -0,0 +1,337 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Implementation of non-inlined API in neuron_recording.h +#include "meanfield_recording.h" + +#include +#include + +//! The index to record each variable to for each neuron +uint8_t **neuron_recording_indexes; + +//! The index to record each bitfield variable to for each neuron +uint8_t **bitfield_recording_indexes; + +//! An array of recording information structures +recording_info_t *recording_info; + +//! An array of bitfield information structures +bitfield_info_t *bitfield_info; + +//! An array of spaces into which recording values can be written +uint8_t **recording_values; + +//! An array of spaces into which bitfields can be written +uint32_t **bitfield_values; + +//! The number of recordings outstanding +volatile uint32_t n_recordings_outstanding = 0; + +//! The address of the recording region to read on reset +static void *reset_address; + +//! When bitwise anded with a number will floor to the nearest multiple of 4 +#define FLOOR_TO_4 0xFFFFFFFC + +//! Add to a number before applying floor to 4 to turn it into a ceil operation +#define CEIL_TO_4 3 + +//! \brief resets all states back to start state. +static void reset_record_counter(void) { + for (uint32_t i = 0; i < N_RECORDED_VARS; i++) { + if (recording_info[i].rate == 0) { + // Setting increment to zero means count will never equal rate + recording_info[i].increment = 0; + + // Count is not rate so does not record, but not 1 so it does not reset! + recording_info[i].count = 2; + } else { + // Increase one each call so count gets to rate + recording_info[i].increment = 1; + + // Using rate here so that the zero time is recorded + recording_info[i].count = recording_info[i].rate; + } + } + + // clear the bitfields + for (uint32_t i = 0; i < N_BITFIELD_VARS; i++) { + if (bitfield_info[i].rate == 0) { + // Setting increment to zero means count will never equal rate + bitfield_info[i].increment = 0; + + // Count is not rate so does not record, but not 1 so it does not reset! + bitfield_info[i].count = 2; + } else { + // Increase one each call so count gets to rate + bitfield_info[i].increment = 1; + + // Using rate here so that the zero time is recorded + bitfield_info[i].count = bitfield_info[i].rate; + clear_bit_field(bitfield_info[i].values->bits, + bitfield_info[i].n_words); + } + } +} + +//! \brief wrapper to recording finalise +void neuron_recording_finalise(void) { + recording_finalise(); +} + +//! \brief the number of bytes used in bitfield recording for n_neurons +//! \param[in] n_neurons: The number of neurons to create a bitfield for +//! \return the size of the bitfield data structure for the number of neurons +static inline uint32_t bitfield_data_size(uint32_t n_neurons) { + return sizeof(bitfield_values_t) + (get_bit_field_size(n_neurons) * sizeof(uint32_t)); +} + +//! \brief reads recording data from SDRAM +//! \param[in] recording_address: SDRAM location for the recording data +//! \param[in] n_neurons: the number of neurons to setup for +//! \return Whether the read was successful +static bool neuron_recording_read_in_elements( + void *recording_address, uint32_t n_neurons) { + // Round up the number of bytes to align at a word boundary i.e. round to + // the next multiple of 4 + uint32_t ceil_n_entries = (n_neurons + CEIL_TO_4) & FLOOR_TO_4; + + // GCC lets you define a struct like this! + typedef struct neuron_recording_data { + uint32_t rate; + uint32_t n_neurons_recording; + uint32_t element_size; + uint8_t indices[ceil_n_entries]; + } neuron_recording_data_t; + + neuron_recording_data_t *data = recording_address; + + for (uint32_t i = 0; i < N_RECORDED_VARS; i++) { + recording_info[i].rate = data[i].rate; + uint32_t n_neurons_rec = data[i].n_neurons_recording; + recording_info[i].element_size = data[i].element_size; + recording_info[i].size = sizeof(recording_values_t) + + (n_neurons_rec * recording_info[i].element_size); + // There is an extra "neuron" in the data used when one of the neurons + // is *not* recording, to avoid a check + uint32_t alloc_size = recording_info[i].size + + recording_info[i].element_size; + + // allocate memory for the recording + if (recording_info[i].values == NULL) { + recording_info[i].values = spin1_malloc(alloc_size); + if (recording_info[i].values == NULL) { + log_error("couldn't allocate recording data space for %d", i); + return false; + } + recording_values[i] = recording_info[i].values->data; + } + + // copy over the indexes + spin1_memcpy(neuron_recording_indexes[i], data[i].indices, + n_neurons * sizeof(uint8_t)); + } + + typedef struct bitfield_recording_data { + uint32_t rate; + uint32_t n_neurons_recording; + uint8_t indices[ceil_n_entries]; + } bitfield_recording_data_t; + + bitfield_recording_data_t *bitfield_data = + (bitfield_recording_data_t *) &data[N_RECORDED_VARS]; + + for (uint32_t i = 0; i < N_BITFIELD_VARS; i++) { + bitfield_info[i].rate = bitfield_data[i].rate; + uint32_t n_neurons_rec = bitfield_data[i].n_neurons_recording; + bitfield_info[i].size = bitfield_data_size(n_neurons_rec); + // There is an extra "neuron" in the data used when one of the neurons + // is *not* recording, to avoid a check + uint32_t alloc_size = bitfield_data_size(n_neurons_rec + 1); + + // allocate memory for the recording + if (bitfield_info[i].values == NULL) { + bitfield_info[i].values = spin1_malloc(alloc_size); + if (bitfield_info[i].values == NULL) { + log_error("couldn't allocate bitfield recording data space for %d", i); + return false; + } + // There is an extra "neuron" in the data used when one of the + // neurons is *not* recording, to avoid a check + bitfield_info[i].n_words = get_bit_field_size(n_neurons_rec + 1); + bitfield_values[i] = bitfield_info[i].values->bits; + } + + // copy over the indexes + spin1_memcpy(bitfield_recording_indexes[i], bitfield_data[i].indices, + n_neurons * sizeof(uint8_t)); + } + return true; +} + +bool neuron_recording_reset(uint32_t n_neurons) { + recording_reset(); + if (!neuron_recording_read_in_elements(reset_address, n_neurons)) { + log_error("failed to reread in the new elements after reset"); + return false; + } + return true; +} + +//! \brief handles all the DTCM allocations for recording words +//! \param[in] n_neurons: how many neurons to set DTCM for +//! \return True on success +static inline bool allocate_word_dtcm(uint32_t n_neurons) { + recording_info = spin1_malloc(N_RECORDED_VARS * sizeof(recording_info_t)); + if (recording_info == NULL) { + log_error("Could not allocated space for recording_info"); + return false; + } + + // allocate dtcm for the overall holder for indexes + neuron_recording_indexes = + spin1_malloc(N_RECORDED_VARS * sizeof(uint8_t *)); + if (neuron_recording_indexes == NULL) { + log_error("Could not allocate space for var_recording_indexes"); + return false; + } + + recording_values = spin1_malloc(N_RECORDED_VARS * sizeof(uint8_t *)); + if (recording_values == NULL) { + log_error("Could not allocate space for recording_values"); + return false; + } + + for (uint32_t i = 0; i < N_RECORDED_VARS; i++) { + // clear recorded values pointer + recording_info[i].values = NULL; + + // allocate dtcm for indexes for each recording region + neuron_recording_indexes[i] = spin1_malloc(n_neurons * sizeof(uint8_t)); + if (neuron_recording_indexes[i] == NULL) { + log_error("failed to allocate memory for recording index %d", i); + return false; + } + } + + // successfully allocated all DTCM. + return true; +} + +//! \brief handles all the DTCM allocations for recording bitfields +//! \param[in] n_neurons: how many neurons to set DTCM for +//! \return True on success +static inline bool allocate_bitfield_dtcm(uint32_t n_neurons) { + bitfield_info = spin1_malloc(N_BITFIELD_VARS * sizeof(bitfield_info_t)); + if (bitfield_info == NULL) { + log_error("Failed to allocate space for bitfield_info"); + return false; + } + + // allocate dtcm for the overall holder for indexes + bitfield_recording_indexes = + spin1_malloc(N_BITFIELD_VARS * sizeof(uint8_t *)); + if (bitfield_recording_indexes == NULL) { + log_error("Could not allocate space for bitfield_recording_indexes"); + return false; + } + + bitfield_values = spin1_malloc(N_BITFIELD_VARS * sizeof(uint32_t *)); + if (bitfield_values == NULL) { + log_error("Could not allocate space for bitfield_values"); + return false; + } + + for (uint32_t i = 0; i < N_BITFIELD_VARS; i++) { + // clear recorded values pointer + bitfield_info[i].values = NULL; + + // allocate dtcm for indexes for each recording region + bitfield_recording_indexes[i] = + spin1_malloc(n_neurons * sizeof(uint8_t)); + if (bitfield_recording_indexes[i] == NULL) { + log_error("failed to allocate memory for bitfield index %d", i); + return false; + } + } + + // successfully allocated all DTCM. + return true; +} + +//! The heading of the neuron recording region. +typedef struct neuron_recording_header { + //! The number of word-sized variables to record + uint32_t n_recorded_vars; + //! The number of bitfield variables to record + uint32_t n_bitfield_vars; +} neuron_recording_header_t; + +bool neuron_recording_initialise( + void *recording_address, uint32_t *recording_flags, + uint32_t n_neurons, uint32_t *n_rec_regions_used) { + // boot up the basic recording + void *data_addr = recording_address; + bool success = recording_initialize(&data_addr, recording_flags); + if (!success) { + log_error("failed to init basic recording."); + return false; + } + + // Verify the number of recording and bitfield elements + neuron_recording_header_t *header = data_addr; + if (header->n_recorded_vars != N_RECORDED_VARS) { + log_error("Data spec number of recording variables %d != " + "neuron implementation number of recorded variables %d", + header->n_recorded_vars, N_RECORDED_VARS); + return false; + } + if (header->n_bitfield_vars != N_BITFIELD_VARS) { + log_error("Data spec number of bitfield variables %d != " + "neuron implementation number of bitfield variables %d", + header->n_bitfield_vars, N_BITFIELD_VARS); + return false; + } + // Copy the number of regions used + *n_rec_regions_used = header->n_recorded_vars + header->n_bitfield_vars; + data_addr = &header[1]; + log_debug("Recording %d variables and %d bitfield variables", + N_RECORDED_VARS, N_BITFIELD_VARS); + + if (!allocate_word_dtcm(n_neurons)) { + log_error("failed to allocate DTCM for the neuron recording structs."); + return false; + } + if (!allocate_bitfield_dtcm(n_neurons)) { + log_error("failed to allocate DTCM for the bitfield recording structs"); + return false; + } + + // read in the sdram params into the allocated data objects + reset_address = data_addr; + if (!neuron_recording_read_in_elements(data_addr, n_neurons)) { + log_error("failed to read in the elements"); + return false; + } + + // reset stuff + reset_record_counter(); + + return true; +} diff --git a/neural_modelling/src/meanfield_fixing/meanfield_recording.h b/neural_modelling/src/meanfield_fixing/meanfield_recording.h new file mode 100644 index 00000000000..61b7b1f99f4 --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/meanfield_recording.h @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2019-2020 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Recording of the state of a neuron (spiking, voltage, etc.) + +#ifndef _MEANFIELD_RECORDING_H_ +#define _MEANFIELD_RECORDING_H_ + +#include +#include +#include +#include + +//#include "implementations/meanfield_impl_standard.h" + + +//! A struct of the different types of recorded data +// Note data is just bytes here but actual type is used on writing +typedef struct recording_values_t { + uint32_t time; + uint8_t data[]; +} recording_values_t; + +//! A struct for bitfield data +typedef struct bitfield_values_t { + uint32_t time; + uint32_t bits[]; +} bitfield_values_t; + +//! A struct for information for a non-bitfield recording +typedef struct recording_info_t { + uint32_t element_size; + uint32_t rate; + uint32_t count; + uint32_t increment; + uint32_t size; + recording_values_t *values; +} recording_info_t; + +//! A struct for information on a bitfield recording +typedef struct bitfield_info_t { + uint32_t rate; + uint32_t count; + uint32_t increment; + uint32_t size; + uint32_t n_words; + bitfield_values_t *values; +} bitfield_info_t; + +//! The index to record each variable to for each neuron +extern uint8_t **neuron_recording_indexes; + +//! The index to record each bitfield variable to for each neuron +extern uint8_t **bitfield_recording_indexes; + +//! An array of recording information structures +extern recording_info_t *recording_info; + +//! An array of bitfield information structures +extern bitfield_info_t *bitfield_info; + +//! An array of spaces into which recording values can be written +extern uint8_t **recording_values; + +//! An array of spaces into which bitfields can be written +extern uint32_t **bitfield_values; + +//! \brief stores a recording of a value of any type, except bitfield; +//! use the functions below for common types as these will be faster. +//! \param[in] var_index: which recording variable to write this is +//! \param[in] neuron_index: the neuron id for this recorded data +//! \param[in] value: pointer to the value to record for this neuron. +static inline void neuron_recording_record_value( + uint32_t var_index, uint32_t neuron_index, void *value) { + uint32_t index = neuron_recording_indexes[var_index][neuron_index]; + uint32_t size = recording_info[var_index].element_size; + uint32_t p = size * index; + spin1_memcpy(&recording_values[var_index][p], value, size); +} + +//! \brief stores a recording of an accum variable only; this is faster than +//! neuron_recording_record_value for this type +//! \param[in] var_index: which recording variable to write this is +//! \param[in] neuron_index: the neuron id for this recorded data +//! \param[in] value: the results to record for this neuron. +static inline void neuron_recording_record_accum( + uint32_t var_index, uint32_t neuron_index, accum value) { + uint8_t index = neuron_recording_indexes[var_index][neuron_index]; + accum *data = (accum *) recording_values[var_index]; + data[index] = value; +} + +//! \brief stores a recording of a double variable only; this is faster than +//! neuron_recording_record_value for this type +//! \param[in] var_index: which recording variable to write this is +//! \param[in] neuron_index: the neuron id for this recorded data +//! \param[in] value: the results to record for this neuron. +static inline void neuron_recording_record_double( + uint32_t var_index, uint32_t neuron_index, double value) { + uint8_t index = neuron_recording_indexes[var_index][neuron_index]; + double *data = (double *) recording_values[var_index]; + data[index] = value; +} + +//! \brief stores a recording of a float variable only; this is faster than +//! neuron_recording_record_value for this type +//! \param[in] var_index: which recording variable to write this is +//! \param[in] neuron_index: the neuron id for this recorded data +//! \param[in] value: the results to record for this neuron. +static inline void neuron_recording_record_float( + uint32_t var_index, uint32_t neuron_index, float value) { + uint8_t index = neuron_recording_indexes[var_index][neuron_index]; + float *data = (float *) recording_values[var_index]; + data[index] = value; +} + +//! \brief stores a recording of an int32_t variable only; this is faster than +//! neuron_recording_record_value for this type +//! \param[in] var_index: which recording variable to write this is +//! \param[in] neuron_index: the neuron id for this recorded data +//! \param[in] value: the results to record for this neuron. +static inline void neuron_recording_record_int32( + uint32_t var_index, uint32_t neuron_index, int32_t value) { + uint8_t index = neuron_recording_indexes[var_index][neuron_index]; + int32_t *data = (int32_t *) recording_values[var_index]; + data[index] = value; +} + + +//! \brief stores a recording of a set bit; this is the only way to set a bit +//! in a bitfield; neuron_recording_record_value doesn't work for this! +//! \param[in] var_index: which bitfield recording variable to write this is +//! \param[in] neuron_index: which neuron to set the bit for +static inline void neuron_recording_record_bit( + uint32_t var_index, uint32_t neuron_index) { + // Record the bit + uint32_t index = neuron_recording_indexes[var_index][neuron_index]; + bit_field_set(bitfield_values[var_index], index); +} + +//! \brief does the recording process of handing over to basic recording +//! \param[in] time: the time to put into the recording stamps. +static inline void neuron_recording_record(uint32_t time) { + // go through all recordings + for (uint32_t i = N_RECORDED_VARS; i > 0; i--) { + recording_info_t *rec_info = &recording_info[i - 1]; + // if the rate says record, record now + if (rec_info->count == rec_info->rate) { + // Reset the count + rec_info->count = 1; + // Set the time and record the data + rec_info->values->time = time; + recording_record(i - 1, rec_info->values, rec_info->size); + } else { + + // Not recording this time, so increment by specified amount + rec_info->count += rec_info->increment; + } + } + + for (uint32_t i = N_BITFIELD_VARS; i > 0; i--) { + bitfield_info_t *bf_info = &bitfield_info[i - 1]; + // if the rate says record, record now + if (bf_info->count == bf_info->rate) { + // Reset the count + bf_info->count = 1; + // Skip empty bitfields + if (empty_bit_field(bf_info->values->bits, bf_info->n_words)) { + continue; + } + // Set the time and record the data (note index is after recorded_vars) + bf_info->values->time = time; + recording_record(i + N_RECORDED_VARS - 1, bf_info->values, bf_info->size); + } else { + + // Not recording this time, so increment by specified amount + bf_info->count += bf_info->increment; + } + } +} + +//! \brief sets up state for next recording. +static inline void neuron_recording_setup_for_next_recording(void) { + // Reset the bitfields before starting if a beginning of recording + for (uint32_t i = N_BITFIELD_VARS; i > 0; i--) { + bitfield_info_t *b_info = &bitfield_info[i - 1]; + if (b_info->count == 1) { + clear_bit_field(b_info->values->bits, b_info->n_words); + } + } +} + +//! \brief reads recording data from sdram on reset. +//! \param[in] n_neurons: the number of neurons to setup for +//! \return bool stating if the read was successful or not +bool neuron_recording_reset(uint32_t n_neurons); + +//! \brief sets up the recording stuff +//! \param[in] recording_address: sdram location for the recording data +//! \param[out] recording_flags: Output of flags which can be used to check if +//! a channel is enabled for recording +//! \param[in] n_neurons: the number of neurons to setup for +//! \param[out] n_rec_regions_used: Output the number of regions used by neuron +//! recording +//! \return bool stating if the init was successful or not +bool neuron_recording_initialise( + void *recording_address, uint32_t *recording_flags, + uint32_t n_neurons, uint32_t *n_rec_regions_used); + +//! \brief finishes recording +void neuron_recording_finalise(void); + +#endif //_NEURON_RECORDING_H_ diff --git a/neural_modelling/src/meanfield_fixing/models/config.h b/neural_modelling/src/meanfield_fixing/models/config.h new file mode 100644 index 00000000000..6c1d31e291d --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/models/config.h @@ -0,0 +1,73 @@ +#ifndef _CONFIG_H_ +#define _CONFIG_H_ + +#include "meanfield_model.h" + + +/*struct config_t; +typedef struct config_t config_t; +typedef struct config_t* config_t;*/ + +typedef struct config_t { + // nominally 'fixed' parameters + REAL pconnec; + REAL Qe; + REAL Qi; + REAL Te; + REAL Ti; + REAL Ee; + REAL Ei; + REAL Ntot; + REAL gei; + REAL ext_drive; + REAL afferent_exc_fraction; + + REAL Gl; + REAL Cm; + REAL El; + + REAL P0; + REAL P1; + REAL P2; + REAL P3; + REAL P4; + REAL P5; + REAL P6; + REAL P7; + REAL P8; + REAL P9; + REAL P10; + + // Variable-state parameters + //REAL fe; + //REAL fi; + + REAL muV;//:=0.0; + REAL muV0; + //muV0 = -60e-3; + REAL DmuV0;// = 10e-3; + + REAL sV;//=0.0; + REAL sV0;// = 4e-3; + REAL DsV0;// = 6e-3; + + REAL muGn;//=0.0; + + REAL TvN;//=0.0; + REAL TvN0;// = 0.5; + REAL DTvN0;// = 1.; + + REAL Vthre;//=0.0; + + REAL Fout_th;//=0.0; +} config_t; + +/* +typedef struct global_toolbox_params_t { + REAL this_h; + REAL this_time; +} global_toolbox_params_t; +*/ + + +#endif \ No newline at end of file diff --git a/neural_modelling/src/meanfield_fixing/models/mathsbox.h b/neural_modelling/src/meanfield_fixing/models/mathsbox.h new file mode 100644 index 00000000000..dc6abf625f9 --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/models/mathsbox.h @@ -0,0 +1,23 @@ +#ifndef _MATHSBOX_H_ +#define _MATHSBOX_H_ + +#include +#include +#include +//#include + + + +struct mathsbox_t; + +typedef struct mathsbox_t { + + REAL error_func_sample; + + REAL err_func; +}mathsbox_t; + +//typedef struct mathsbox_params_t* mathsbox_pointer_t; + +void error_function(REAL x, REAL factor, mathsbox_t *restrict mathsbox); +#endif \ No newline at end of file diff --git a/neural_modelling/src/meanfield_fixing/models/meanfield_model.h b/neural_modelling/src/meanfield_fixing/models/meanfield_model.h new file mode 100644 index 00000000000..7c65d7c4160 --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/models/meanfield_model.h @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/*! + * \dir + * \brief Neuronal Soma Models. + * \file + * \brief The API for neuron models themselves. + */ + +#ifndef _MEANFIELD_MODEL_H_ +#define _MEANFIELD_MODEL_H_ + +#include + +//! Forward declaration of neuron type (creates a definition for a pointer to a +//! neuron parameter struct +struct meanfield_t; +typedef struct meanfield_t meanfield_t; +typedef struct meanfield_t* meanfield_pointer_t; + +struct config_t; +typedef struct config_t config_t; +typedef struct config_t* config_pointer_t; + +struct mathsbox_t; +typedef struct mathsbox_t mathsbox_t; +typedef struct mathsbox_t* mathsbox_pointer_t; + +//! Forward declaration of global neuron parameters +struct global_neuron_params_t; +typedef struct global_neuron_params_t global_neuron_params_t; +//! pointer to global neuron parameters +typedef global_neuron_params_t* global_neuron_params_pointer_t; + +//! \brief set the global neuron parameters +//! \param[in] params: The parameters to set +void meanfield_model_set_global_neuron_params( + const global_neuron_params_t *params); + +//! \brief primary function called in timer loop after synaptic updates +//! \param[in] num_excitatory_inputs: Number of excitatory receptor types. +//! \param[in] exc_input: Pointer to array of inputs per receptor type received +//! this timer tick that produce a positive reaction within the neuron in +//! terms of stimulation. +//! \param[in] num_inhibitory_inputs: Number of inhibitory receptor types. +//! \param[in] inh_input: Pointer to array of inputs per receptor type received +//! this timer tick that produce a negative reaction within the neuron in +//! terms of stimulation. +//! \param[in] external_bias: This is the intrinsic plasticity which could be +//! used for ac, noisy input etc etc. (general purpose input) +//! \param[in,out] neuron: the pointer to a neuron parameter struct which +//! contains all the parameters for a specific neuron +//! \return the value to be compared with a threshold value to determine if the +//! neuron has spiked +/* +state_t meanfield_model_state_update( + uint16_t num_excitatory_inputs, const input_t *exc_input, + uint16_t num_inhibitory_inputs, const input_t *inh_input, + input_t external_bias, meanfield_t *restrict meanfield, + config_t *restrict config); +*/ + + + +state_t meanfield_model_state_update( + meanfield_t *restrict meanfield, config_t *restrict config, mathsbox_t *restrict mathsbox); + +//! \brief Indicates that the neuron has spiked +//! \param[in, out] neuron pointer to a neuron parameter struct which contains +//! all the parameters for a specific neuron +void neuron_model_has_spiked(meanfield_t *restrict meanfield); + +//! \brief get the neuron membrane voltage for a given neuron parameter set +//! \param[in] neuron: a pointer to a neuron parameter struct which contains +//! all the parameters for a specific neuron +//! \return the membrane voltage for a given neuron with the neuron +//! parameters specified in neuron +state_t meanfield_model_get_firing_rate(const meanfield_t *meanfield); + +//! \brief printout of state variables i.e. those values that might change +//! \param[in] neuron: a pointer to a neuron parameter struct which contains all +//! the parameters for a specific neuron +void meanfield_model_print_state_variables(const meanfield_t *meanfield); + +//! \brief printout of parameters i.e. those values that don't change +//! \param[in] neuron: a pointer to a neuron parameter struct which contains all +//! the parameters for a specific neuron +void meanfield_model_print_parameters(const meanfield_t *meanfield); + +#endif // _NEURON_MODEL_H_ diff --git a/neural_modelling/src/meanfield_fixing/models/meanfield_model_impl.c b/neural_modelling/src/meanfield_fixing/models/meanfield_model_impl.c new file mode 100644 index 00000000000..c3a7c296db6 --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/models/meanfield_model_impl.c @@ -0,0 +1,440 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Izhekevich neuron implementation +#include "meanfield_model_impl.h" +#include "mathsbox.h" +#include "config.h" + +#include + +//! The global parameters of the Izhekevich neuron model +static const global_neuron_params_t *global_params; + +/*! \brief For linear membrane voltages, 1.5 is the correct value. However + * with actual membrane voltage behaviour and tested over an wide range of + * use cases 1.85 gives slightly better spike timings. + */ +//static const REAL SIMPLE_TQ_OFFSET = REAL_CONST(1.85); +/* +///////////////////////////////////////////////////////////// +#if 0 +// definition for Izhikevich neuron +static inline void neuron_ode( + REAL t, REAL stateVar[], REAL dstateVar_dt[], + neuron_t *neuron, REAL input_this_timestep) { + REAL V_now = stateVar[1]; + REAL U_now = stateVar[2]; + log_debug(" sv1 %9.4k V %9.4k --- sv2 %9.4k U %9.4k\n", stateVar[1], + neuron->V, stateVar[2], neuron->U); + + // Update V + dstateVar_dt[1] = + REAL_CONST(140.0) + + (REAL_CONST(5.0) + REAL_CONST(0.0400) * V_now) * V_now - U_now + + input_this_timestep; + + // Update U + dstateVar_dt[2] = neuron->A * (neuron->B * V_now - U_now); +} +#endif +*/ + +//! \brief The original model uses 0.04, but this (1 ULP larger?) gives better +//! numeric stability. +//! +//! Thanks to Mantas Mikaitis for this! +//static const REAL MAGIC_MULTIPLIER = REAL_CONST(0.040008544921875); + + +/* #################################################################### + reuse of izk for meanfields + ################################################################### + */ + +void error_function( REAL x, REAL factor, mathsbox_t *restrict mathsbox){ +//devra coder fonction powerof + + REAL dt = x/mathsbox->error_func_sample; + REAL t; + REAL Pi = 3.1415927; + REAL Erfc = mathsbox->err_func; + for(t=0; t==x; t+=dt){ + //Erfc += dt; //test otherwise IDTM overload + //Erfc += factor*(2/sqrtk(Pi))*expk(-(t*t)); // the real one + Erfc += factor+t*t;//fake one + } + + mathsbox->err_func = Erfc; + + //return Erfc; + +} + + +void threshold_func(config_t *restrict config) +{ + /* + setting by default to True the square + because when use by external modules, coeff[5:]=np.zeros(3) + in the case of a linear threshold + */ + /*NEED TO AVOID DIVISION AS POSSIBLE + but not for now + */ + /* + config->muV0=-0.06; + config->DmuV0=0.01; + + config->sV0=0.004; + config->DsV0=0.006; + + config->TvN0=0.5; + config->DTvN0=1.; + + config->muV=0.; + config->sV=0.; + config->muGn=0.; + config->TvN=0.; + config->Vthre=0.; + config->Fout_th=0.; + */ + + // + 0.\ //P4*np.log(muGn) + /* + config->Vthre = config->P0\ + + config->P1*(config->muV-config->muV0)/config->DmuV0\ + + config->P2*(config->sV-config->sV0)/config->DsV0\ + + config->P3*(config->TvN-config->TvN0)/config->DTvN0\ + + config->P5*((config->muV-config->muV0)/config->DmuV0)*((config->muV-config->muV0)/config->DmuV0)\ + + config->P6*((config->sV-config->sV0)/config->DsV0)*((config->sV-config->sV0)/config->DsV0)\ + + config->P7*((config->TvN-config->TvN0)/config->DTvN0)*((config->TvN-config->TvN0)/config->DTvN0)\ + + config->P8*(config->muV-config->muV0)/config->DmuV0*(config->sV-config->sV0)/config->DsV0\ + + config->P9*(config->muV-config->muV0)/config->DmuV0*(config->TvN-config->TvN0)/config->DTvN0\ + + config->P10*(config->sV-config->sV0)/config->DsV0*(config->TvN-config->TvN0)/config->DTvN0; + */ + + config->Vthre = config->P0; + + //return config->Vthre; + + } + +/* + REAL ONE get_fluct_regime_varsup +*/ +/* +void get_fluct_regime_varsup(REAL Ve, REAL Vi, config_t *restrict params) +{ + //takes 880 bytes overflowed ITCM + + REAL Fe; + REAL Fi; + REAL muGe, muGi, muG; + REAL Ue, Ui; + REAL Tm, Tv; + + + // here TOTAL (sum over synapses) excitatory and inhibitory input + + Fe = Ve * (1.-params->gei)*params->pconnec*params->Ntot; // default is 1 !! + Fi = Vi * params->gei*params->pconnec*params->Ntot; + + muGe = params->Qe*params->Te*Ve; + muGi = params->Qi*params->Ti*Vi; + + muG = params->Gl+muGe+muGi; + + params->muV = (muGe*params->Ee+muGi*params->Ei+params->Gl*params->El)/muG; + + + params->muGn = muG/params->Gl; + + Tm = params->Cm/muG; + + Ue = params->Qe/muG*(params->Ee-params->muV); + Ui = params->Qi/muG*(params->Ei-params->muV); + + + //PENSEZ a enlever autant de division que possible + + params->sV = sqrtk(Fe*(Ue*params->Te)*(Ue*params->Te)/2./(params->Te+Tm)+\ + Fi*(params->Ti*Ui)*(params->Ti*Ui)/2./(params->Ti+Tm)); + + if (params->sV < 1e-8){ + params->sV = 1e-8; + } + + if (Fe<1e-9)//just to insure a non zero division, + { + Fe += 1e-9; + } + else if (Fi<1e-9) + { + Fi += 1e-9; + } + + Tv = ( Fe*(Ue*params->Te)*(Ue*params->Te) + Fi*(params->Ti*Ui)*(params->Ti*Ui))\ + /(Fe*(Ue*params->Te)*(Ue*params->Te)/(params->Te+Tm)\ + + Fi*(params->Ti*Ui)*(params->Ti*Ui)/(params->Ti+Tm)); + + params->TvN = Tv*params->Gl/params->Cm; + + //return params->muV;//, sV+1e-12, muGn, TvN +} +*/ + + +// FAKE ONE get_fluct_regime_varsup +//where all division are removed + +void get_fluct_regime_varsup(REAL Ve, REAL Vi, config_t *restrict params) +{ + //takes 880 bytes overflowed ITCM + + REAL Fe; + REAL Fi; + REAL muGe, muGi, muG; + REAL Ue, Ui; + REAL Tm, Tv; + + + // here TOTAL (sum over synapses) excitatory and inhibitory input + + Fe = Ve * (1.-params->gei)*params->pconnec*params->Ntot; // default is 1 !! + Fi = Vi * params->gei*params->pconnec*params->Ntot; + + muGe = params->Qe*params->Te*Ve; + muGi = params->Qi*params->Ti*Vi; + + muG = params->Gl+muGe+muGi; + + params->muV = (muGe*params->Ee+muGi*params->Ei+params->Gl*params->El); //fake one + + params->muGn = muG; //fake one + + Tm = params->Cm/muG; //fake one + + Ue = params->Qe; //fake one + Ui = params->Qi; //fake one + + + //PENSEZ a enlever autant de division que possible + + params->sV = Fe*(Ue*params->Te)*(Ue*params->Te)+\ + Fi*(params->Ti*Ui)*(params->Ti*Ui);// fake one + + if (params->sV < 1e-8){ + params->sV = 1e-8; + } + + if (Fe<1e-9)//just to insure a non zero division, + { + Fe += 1e-9; + } + else if (Fi<1e-9) + { + Fi += 1e-9; + } + + Tv = ( Fe*(Ue*params->Te)*(Ue*params->Te) +\ + Fi*(params->Ti*Ui)*(params->Ti*Ui)); //fake one + + params->TvN = Tv*params->Gl; //fake one + + + //return params->muV;//, sV+1e-12, muGn, TvN +} + +//END of the get_fluct_regime_varsup FAKE + + + +void TF(REAL Ve, REAL Vi, meanfield_t *meanfield, config_t *restrict config, mathsbox_t *restrict mathsbox){ + +// argument are fe, fi and pseq_params +// problem is to implement it with params and instruction coming from +// DTCM and ITCM. +// when get_fluct_regime_varsup is ON takes 1360 bytes overflowed ITCM + + + REAL limit; + REAL argument; + + if (Ve < REAL_CONST(1e-8)){ + Ve = REAL_CONST(1e-8); + } + if (Vi < REAL_CONST(1e-8)){ + Vi = REAL_CONST(1e-8); + } + + get_fluct_regime_varsup(Ve, Vi, config); + threshold_func(config); + + if (config->sVsV = REAL_CONST(1e-4); + } + + limit = 10;//REAL_HALF(config->Gl/(config->TvN * config->Cm)); + argument = config->Vthre;//(config->Vthre - config->muV)/sqrtk(REAL_CONST(2.))/config->sV; + +// config->Fout_th = error_function(factor, argument, mathsbox); + error_function(limit, argument, mathsbox); + + + if (config->Fout_th < REAL_CONST(1e-8)){ + config->Fout_th = REAL_CONST(1e-8); + } + + //return config->Fout_th; +} + + +void RK2_midpoint_MF(REAL h, meanfield_t *meanfield, config_t *restrict config, mathsbox_t *restrict mathsbox) { +/* need to input T_inv time scale where the 1/T will be done (and rounding) +on the user computer before send it to the DTCM. +*/ + REAL lastVe = meanfield->Ve; + REAL T_inv = meanfield->Timescale_inv; + //TF(lastVe,1.,meanfield, config, mathsbox); + REAL lastTF = 1.0; //config->Fout_th; + + + //configVe stand for TF1 i.e TF for exitatory pop. SO configVi is for TF2 + //In fact no configVe and configVi just config, all in the same file. + + + /*meanfield->Ve += lastVe\ + + REAL_HALF(TF(lastVe,1,meanfield, config, mathsbox) - lastVe)\ + *(REAL_CONST(2.0)-h)*h; + */ + + meanfield->Ve += lastVe\ + + REAL_HALF(lastTF - lastVe)\ + *(REAL_CONST(2.0)-h)*h; + meanfield->Ve = meanfield->Ve * T_inv; +} + + +/*############################################################################## +end of reuse +################################################################################# +*/ + +/*! + * \brief Midpoint is best balance between speed and accuracy so far. + * \details From ODE solver comparison work, paper shows that Trapezoid version + * gives better accuracy at small speed cost + * \param[in] h: threshold + * \param[in,out] neuron: The model being updated + * \param[in] input_this_timestep: the input + */ +/*static inline void rk2_kernel_midpoint( + REAL h, neuron_t *neuron, REAL input_this_timestep) { + // to match Mathematica names + REAL lastV1 = neuron->V; + REAL lastU1 = neuron->U; + REAL a = neuron->A; + REAL b = neuron->B; + + REAL pre_alph = REAL_CONST(140.0) + input_this_timestep - lastU1; + REAL alpha = pre_alph + + (REAL_CONST(5.0) + MAGIC_MULTIPLIER * lastV1) * lastV1; + REAL eta = lastV1 + REAL_HALF(h * alpha); + + // could be represented as a long fract? + REAL beta = REAL_HALF(h * (b * lastV1 - lastU1) * a); + + neuron->V += h * (pre_alph - beta + + (REAL_CONST(5.0) + MAGIC_MULTIPLIER * eta) * eta); + + neuron->U += a * h * (-lastU1 - beta + b * eta); +} +*/ + + +void meanfield_model_set_global_neuron_params( + const global_neuron_params_t *params) { + global_params = params; +} + +/*perhaps when we will do more than one MF we could uses "num_excitatory_inputs" like the number of ex MF and in MF? + and maybe is there some contamanation from the neightbourest neighbour MF! +*/ +state_t meanfield_model_state_update( + meanfield_t *restrict meanfield, config_t *restrict config, mathsbox_t *restrict mathsbox){ + /* + uint16_t num_excitatory_inputs, const input_t *exc_input, + uint16_t num_inhibitory_inputs, const input_t *inh_input, + input_t external_bias, meanfield_t *restrict meanfield, + config_t *restrict config) { + REAL total_exc = 0; + REAL total_inh = 0; + + for (int i =0; iI_offset; + */ + + // the best AR update so far + RK2_midpoint_MF(meanfield->this_h, meanfield, config, mathsbox); + meanfield->this_h = global_params->machine_timestep_ms; + + return meanfield->Ve; +} + + + +void neuron_model_has_spiked(meanfield_t *restrict meanfield) { + log_debug("in neuron_model_has_spiked, time is ", + global_params->machine_timestep_ms); + // reset membrane voltage + //neuron->V = neuron->C; + + // offset 2nd state variable + //neuron->U += neuron->D; + + // simple threshold correction - next timestep (only) gets a bump + //neuron->this_h = global_params->machine_timestep_ms * SIMPLE_TQ_OFFSET; +} + +//change name neuron -> meanfield and membrane -> rate +state_t meanfield_model_get_firing_rate(const meanfield_t *meanfield) { + return meanfield->Ve; +} + +void meanfield_model_print_state_variables(const meanfield_t *meanfield) { + log_debug("Ve = %11.4k ", meanfield->Ve); + //log_debug("U = %11.4k ", meanfield->Vi); +} + +void meanfield_model_print_parameters(const meanfield_t *meanfield) { + log_debug("Ve = %11.4k ", meanfield->Ve); + //log_debug("Vi = %11.4k ", meanfield->Vi); + //log_debug("B = %11.4k ", neuron->B); + //log_debug("C = %11.4k ", neuron->C); + //log_debug("D = %11.4k ", neuron->D); + + //log_debug("I = %11.4k \n", neuron->I_offset); +} diff --git a/neural_modelling/src/meanfield_fixing/models/meanfield_model_impl.h b/neural_modelling/src/meanfield_fixing/models/meanfield_model_impl.h new file mode 100644 index 00000000000..d33294a39b5 --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/models/meanfield_model_impl.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief meanfield types +#ifndef _MEANFIELD_MODEL_IMPL_H_ +#define _MEANFIELD_MODEL_IMPL_H_ + +#include "meanfield_model.h" + +typedef struct meanfield_t { + // TODO: Parameters - make sure these match with the Python code, + // including the order of the variables when returned by + // get_neural_parameters. + + // + REAL a; + REAL b; + REAL tauw; + REAL Trefrac; + REAL Vthre; + REAL Vreset; + REAL delta_v; + REAL ampnoise; + REAL Timescale_inv; + + REAL Ve; // will be used as a vector !!! OR Ve and Vi + //REAL Vi; + + //vector V = {Ve, Vi}; + + REAL this_h; + + +} meanfield_t; + +typedef struct global_neuron_params_t { + // TODO: Add any parameters that apply to the whole model here (i.e. not + // just to a single neuron) + + // Note: often these are not user supplied, but computed parameters + + //uint32_t machine_time_step; + REAL machine_timestep_ms; +} global_neuron_params_t; + +#endif // _NEURON_MODEL_MY_IMPL_H_ diff --git a/neural_modelling/src/meanfield_fixing/models/my_neuron_model_impl.c b/neural_modelling/src/meanfield_fixing/models/my_neuron_model_impl.c new file mode 100644 index 00000000000..62cee066253 --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/models/my_neuron_model_impl.c @@ -0,0 +1,70 @@ +#include "my_neuron_model_impl.h" + +#include + +// The global parameters of this neuron model +static const global_neuron_params_t *global_params; + +void neuron_model_set_global_neuron_params( + const global_neuron_params_t *params) { + + // TODO: Store parameters as required + global_params = params; +} + +state_t neuron_model_state_update( + uint16_t num_excitatory_inputs, const input_t* exc_input, + uint16_t num_inhibitory_inputs, const input_t* inh_input, + input_t external_bias, neuron_t *restrict neuron) { + + // This takes the input and generates an input value, assumed to be a + // current. Note that the conversion to current from conductance is done + // outside of this function, so does not need to be repeated here. + + // Sum contributions from multiple inputs (if used) + REAL total_exc = 0; + REAL total_inh = 0; + for (uint32_t i = 0; i < num_excitatory_inputs; i++) { + total_exc += exc_input[i]; + } + for (uint32_t i = 0; i < num_inhibitory_inputs; i++) { + total_inh += inh_input[i]; + } + + input_t input_this_timestep = + total_exc - total_inh + external_bias + neuron->I_offset; + + // TODO: Solve your equation here + neuron->V += input_this_timestep; + + log_debug("TESTING TESTING V = %11.4k mv", neuron->V); + + // Return the state variable to be compared with the threshold value + // to determine if the neuron has spikes (commonly the membrane voltage) + // TODO: Update to return the correct variable + return neuron->V; +} + +state_t neuron_model_get_membrane_voltage(const neuron_t *neuron) { + + // TODO: Get the state value representing the membrane voltage + return neuron->V; +} + +void neuron_model_has_spiked(neuron_t *restrict neuron) { + + // TODO: Perform operations required to reset the state after a spike + neuron->V = neuron->my_parameter; +} + +void neuron_model_print_state_variables(const neuron_t *neuron) { + + // TODO: Print all state variables + log_debug("V = %11.4k mv", neuron->V); +} + +void neuron_model_print_parameters(const neuron_t *neuron) { + + // TODO: Print all neuron parameters + log_debug("my parameter = %11.4k mv", neuron->my_parameter); +} diff --git a/neural_modelling/src/meanfield_fixing/models/my_neuron_model_impl.h b/neural_modelling/src/meanfield_fixing/models/my_neuron_model_impl.h new file mode 100644 index 00000000000..7fcb9ccd27d --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/models/my_neuron_model_impl.h @@ -0,0 +1,28 @@ +#ifndef _NEURON_MODEL_MY_IMPL_H_ +#define _NEURON_MODEL_MY_IMPL_H_ + +#include + +typedef struct neuron_t { + // TODO: Parameters - make sure these match with the Python code, + // including the order of the variables when returned by + // get_neural_parameters. + + // Variable-state parameters e.g. membrane voltage + REAL V; + // offset current [nA] + REAL I_offset; + // Put anything else you want to store per neuron + REAL my_parameter; +} neuron_t; + +typedef struct global_neuron_params_t { + // TODO: Add any parameters that apply to the whole model here (i.e. not + // just to a single neuron) + + // Note: often these are not user supplied, but computed parameters + + uint32_t machine_time_step; +} global_neuron_params_t; + +#endif // _NEURON_MODEL_MY_IMPL_H_ diff --git a/neural_modelling/src/meanfield_fixing/plasticity/stdp/maths.h b/neural_modelling/src/meanfield_fixing/plasticity/stdp/maths.h new file mode 100644 index 00000000000..5abfb034b3a --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/plasticity/stdp/maths.h @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Support functions for STDP +#ifndef MATHS_H +#define MATHS_H + +// Standard includes +#include +#include +#include + +//--------------------------------------- +// Macros +//--------------------------------------- +//! \brief Minimum. Evaluates arguments twice +//! \param X: First value +//! \param Y: Second value +//! \return Minimum of two values +#define MIN(X, Y) ((X) < (Y) ? (X) : (Y)) +//! \brief Maximum. Evaluates arguments twice +//! \param X: First value +//! \param Y: Second value +//! \return Maximum of two values +#define MAX(X, Y) ((X) > (Y) ? (X) : (Y)) + +//! \brief Lookup Table of 16-bit integers. +//! +//! Will be padded to a word boundary at the end. +typedef struct int16_lut { + uint16_t size; //!< Number of entries in table + uint16_t shift; //!< Mapping from time to table index + int16_t values[]; //!< Table of actual values +} int16_lut; + +//--------------------------------------- +// Plasticity maths function inline implementation +//--------------------------------------- +//! \brief Copy a Lookup Table from SDRAM to DTCM, updating the address +//! \param[in,out] address: Pointer to the SDRAM address to copy from. This is +//! updated to point to the space after the structure. +//! \return A pointer to the copied lookup table, malloc'd in DTCM +static inline int16_lut *maths_copy_int16_lut(address_t *address) { + int16_lut *sdram_lut = (int16_lut *) *address; + uint32_t size = sizeof(int16_lut) + (sdram_lut->size * sizeof(int16_t)); + int16_lut *lut = spin1_malloc(size); + if (lut == NULL) { + log_error("Not enough space to allocate LUT. Try reducing the timestep," + " the number of neurons per core, or the tau value"); + rt_error(RTE_SWERR); + } + spin1_memcpy(lut, sdram_lut, size); + + // Pad to number of words (+ 1 for size / shift header) + const uint32_t num_words = (lut->size / 2) + (((lut->size & 1) != 0) ? 1 : 0); + *address += num_words + 1; + + return lut; +} + +//! \brief Get value from lookup table +//! \param[in] time: The time that we are mapping +//! \param[in] lut: The lookup table (result of maths_copy_int16_lut()) +//! \return The value from the LUT, or zero if out of range +static inline int32_t maths_lut_exponential_decay( + uint32_t time, const int16_lut *lut) { + // Calculate lut index + uint32_t lut_index = time >> lut->shift; + + // Return value from LUT + return (lut_index < lut->size) ? lut->values[lut_index] : 0; +} + +//! \brief Clamp to fit in number of bits +//! \param[in] x: The value to clamp +//! \param[in] shift: Width of the field to clamp the value to fit in +//! \return The clamped value +static inline int32_t maths_clamp_pot(int32_t x, uint32_t shift) { + uint32_t y = x >> shift; + if (y) { + x = ~y >> (32 - shift); + } + + return x; +} + +//--------------------------------------- +//! \brief multiply two 16-bit numbers to get a 32-bit number. +//! +//! **NOTE:** this should 'encourage' GCC to insert SMULxy 16x16 multiply +//! +//! \param[in] x: The first multiplicand +//! \param[in] y: The first multiplicand +//! \return The product +static inline int32_t maths_mul_16x16(int16_t x, int16_t y) { + return x * y; +} + +//--------------------------------------- +//! \brief multiply two 16-bit fixed point numbers (encoded in int32_t) +//! \param[in] a: The first multiplicand +//! \param[in] b: The first multiplicand +//! \param[in] fixed_point_position: The location of the fixed point +//! \return The product +static inline int32_t maths_fixed_mul16( + int32_t a, int32_t b, const int32_t fixed_point_position) { + // Multiply lower 16-bits of a and b together + int32_t mul = __smulbb(a, b); + + // Shift down + return (mul >> fixed_point_position); +} + +//--------------------------------------- +//! \brief multiply two 32-bit fixed point numbers (encoded in int32_t) +//! \param[in] a: The first multiplicand +//! \param[in] b: The first multiplicand +//! \param[in] fixed_point_position: The location of the fixed point +//! \return The product +static inline int32_t maths_fixed_mul32( + int32_t a, int32_t b, const int32_t fixed_point_position) { + int32_t mul = a * b; + + // Shift down and return + return (mul >> fixed_point_position); +} + +#endif // MATHS_H diff --git a/neural_modelling/src/meanfield_fixing/plasticity/stdp/post_events.h b/neural_modelling/src/meanfield_fixing/plasticity/stdp/post_events.h new file mode 100644 index 00000000000..5d2b0cd743e --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/plasticity/stdp/post_events.h @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Post-synaptic events +#ifndef _POST_EVENTS_H_ +#define _POST_EVENTS_H_ + +// Standard includes +#include +#include + +// Include debug header for log_info etc +#include + +//--------------------------------------- +// Macros +//--------------------------------------- +//! Maximum number of post-synaptic events supported +#define MAX_POST_SYNAPTIC_EVENTS 16 + +//--------------------------------------- +// Structures +//--------------------------------------- +//! Trace history of post-synaptic events +typedef struct { + //! Number of events stored (minus one) + uint32_t count_minus_one; + //! Event times + uint32_t times[MAX_POST_SYNAPTIC_EVENTS]; + //! Event traces + post_trace_t traces[MAX_POST_SYNAPTIC_EVENTS]; +} post_event_history_t; + +//! Post event window description +typedef struct { + //! The previous post-synaptic event trace + post_trace_t prev_trace; + //! The previous post-synaptic event time + uint32_t prev_time; + //! The next post-synaptic event trace + const post_trace_t *next_trace; + //! The next post-synaptic event time + const uint32_t *next_time; + //! The number of events + uint32_t num_events; + //! Whether the previous post-synaptic event is valid (based on time) + uint32_t prev_time_valid; +} post_event_window_t; + +//--------------------------------------- +// Inline functions +//--------------------------------------- + +//! \brief Print a post-synaptic event history +//! \param[in] events: The history +static inline void print_event_history(const post_event_history_t *events) { + log_info(" ## printing entire post event history ##"); + for (uint32_t i = 0; i <= events->count_minus_one; i++) { + log_info("post event: %u, time: %u, trace: %u", + i, events->times[i], events->traces[i]); + } +} + +//! \brief Initialise an array of post-synaptic event histories +//! \param[in] n_neurons: Number of neurons +//! \return The array +static inline post_event_history_t *post_events_init_buffers( + uint32_t n_neurons) { + post_event_history_t *post_event_history = + spin1_malloc(n_neurons * sizeof(post_event_history_t)); + // Check allocations succeeded + if (post_event_history == NULL) { + log_error("Unable to allocate global STDP structures - Out of DTCM: Try " + "reducing the number of neurons per core to fix this problem "); + return NULL; + } + + // Loop through neurons + for (uint32_t n = 0; n < n_neurons; n++) { + // Add initial placeholder entry to buffer + post_event_history[n].times[0] = 0; + post_event_history[n].traces[0] = timing_get_initial_post_trace(); + post_event_history[n].count_minus_one = 0; + } + + return post_event_history; +} + +//--------------------------------------- +//! \brief Get the post-synaptic event window +//! \param[in] events: The post-synaptic event history +//! \param[in] begin_time: The start of the window +//! \param[in] end_time: The end of the window +//! \return The window +static inline post_event_window_t post_events_get_window_delayed( + const post_event_history_t *events, uint32_t begin_time, + uint32_t end_time) { + // Start at end event - beyond end of post-event history + const uint32_t count = events->count_minus_one + 1; + const uint32_t *end_event_time = events->times + count; + const uint32_t *event_time = end_event_time; + const post_trace_t *event_trace = events->traces + count; + + post_event_window_t window; + do { + // If this event is still in the future, set it as the end + if (*event_time > end_time) { + end_event_time = event_time; + } + + // Cache pointer to this event as potential next event and go back one + // event. + // **NOTE** next_time can be invalid + window.next_time = event_time--; + window.next_trace = event_trace--; + + // Keep looping while event occurred after start of window and we + // haven't hit beginning of array... + } while (*event_time > begin_time && event_time != events->times); + + // Deference event to use as previous + window.prev_time = *event_time; + window.prev_trace = *event_trace; + window.prev_time_valid = event_time != events->times; + + // Calculate number of events + window.num_events = (end_event_time - window.next_time); + + // Return window + return window; +} + +//--------------------------------------- +//! \brief Advance a post-synaptic event window to the next event +//! \param[in] window: The window to advance +//! \return the advanced window +static inline post_event_window_t post_events_next( + post_event_window_t window) { + // Update previous time and increment next time + window.prev_time = *window.next_time++; + window.prev_trace = *window.next_trace++; + + // Time will now be valid for sure! + window.prev_time_valid = 1; + + // Decrement remaining events + window.num_events--; + return window; +} + +//--------------------------------------- +//! \brief Add a post-synaptic event to the history +//! \param[in] time: the time of the event +//! \param[in,out] events: the history to add to +//! \param[in] trace: the trace of the event +static inline void post_events_add( + uint32_t time, post_event_history_t *events, post_trace_t trace) { + if (events->count_minus_one < MAX_POST_SYNAPTIC_EVENTS - 1) { + // If there's still space, store time at current end + // and increment count minus 1 + const uint32_t new_index = ++events->count_minus_one; + events->times[new_index] = time; + events->traces[new_index] = trace; + } else { + // Otherwise Shuffle down elements + // **NOTE** 1st element is always an entry at time 0 + for (uint32_t e = 2; e < MAX_POST_SYNAPTIC_EVENTS; e++) { + events->times[e - 1] = events->times[e]; + events->traces[e - 1] = events->traces[e]; + } + + // Stick new time at end + events->times[MAX_POST_SYNAPTIC_EVENTS - 1] = time; + events->traces[MAX_POST_SYNAPTIC_EVENTS - 1] = trace; + } +} + +//! \brief Print the post-synaptic event history +//! \param[in] post_event_history: the history +//! \param[in] begin_time: The start time of the history +//! \param[in] end_time: The end time of the history +//! \param[in] delay_dendritic: The amount of dendritic delay +static inline void print_delayed_window_events( + const post_event_history_t *post_event_history, + uint32_t begin_time, uint32_t end_time, uint32_t delay_dendritic) { + log_info(" ## printing post window ##"); + post_event_window_t post_window = post_events_get_window_delayed( + post_event_history, begin_time, end_time); + + while (post_window.num_events > 0) { + const uint32_t delayed_post_time = + *post_window.next_time + delay_dendritic; + log_info("post spike: %u, time: %u, trace: %u", + post_window.num_events, delayed_post_time, + *post_window.next_trace); + + post_window = post_events_next(post_window); + } +} + +#endif // _POST_EVENTS_H_ diff --git a/neural_modelling/src/meanfield_fixing/plasticity/stdp/stdp_typedefs.h b/neural_modelling/src/meanfield_fixing/plasticity/stdp/stdp_typedefs.h new file mode 100644 index 00000000000..0425175c71d --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/plasticity/stdp/stdp_typedefs.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \dir +//! \brief Spike Timing Dependent Plasticity (STDP) +//! \file +//! \brief Basic definitions for STDP +#ifndef _STDP_TYPEDEFS_H_ +#define _STDP_TYPEDEFS_H_ + +//--------------------------------------- +// Macros +//--------------------------------------- +// Fixed-point number system used STDP +//! Position of the point in the fixed point math used by STDP +#define STDP_FIXED_POINT 11 +//! The number 1.0 in the fixed point math used by STDP +#define STDP_FIXED_POINT_ONE (1 << STDP_FIXED_POINT) + +// Helper macros for 16-bit fixed-point multiplication +//! \brief Multiply two STDP fixed point numbers +//! \param[in] a: The first multiplicand +//! \param[in] b: The second multiplicand +//! \return The product +#define STDP_FIXED_MUL_16X16(a, b) maths_fixed_mul16(a, b, STDP_FIXED_POINT) + +#endif // _STDP_TYPEDEFS_H_ diff --git a/neural_modelling/src/meanfield_fixing/plasticity/stdp/synapse_structure/synapse_structure.h b/neural_modelling/src/meanfield_fixing/plasticity/stdp/synapse_structure/synapse_structure.h new file mode 100644 index 00000000000..2c4c23c2625 --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/plasticity/stdp/synapse_structure/synapse_structure.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \dir +//! \brief Synaptic state management +//! \file +//! \brief API for synaptic state +//! +//! Implementations of this have one or more of: +//! * weight +//! * state +//! * accumulator +//! * event window +#ifndef _SYNAPSE_STRUCTURE_H_ +#define _SYNAPSE_STRUCTURE_H_ + +#include + +//! \brief Get the update state from the synapse structure +//! \param[in] synaptic_word: The plastic synapse data +//! \param[in] synapse_type: What (supported) type of synapse is this? +//! \return The update state +static update_state_t synapse_structure_get_update_state( + plastic_synapse_t synaptic_word, index_t synapse_type); + +//! \brief Get the final state from the update state. +//! \param[in] state: the update state +//! \return the final state +static final_state_t synapse_structure_get_final_state( + update_state_t state); + +//! \brief Get the final weight from the final state +//! \param[in] final_state: the final state +//! \return the final weight +static weight_t synapse_structure_get_final_weight( + final_state_t final_state); + +//! \brief Get the final plastic synapse data from the final state +//! \param[in] final_state: the final state +//! \return the final plastic synapse data, ready to be stored +static plastic_synapse_t synapse_structure_get_final_synaptic_word( + final_state_t final_state); + +//! \brief Create the initial plastic synapse data +//! \param[in] weight: the initial synaptic weight +//! \return the plastic synapse data +static plastic_synapse_t synapse_structure_create_synapse(weight_t weight); + +//! \brief Get the current synaptic weight from the plastic synapse data +//! \param[in] synaptic_word: the plastic synapse data +//! \return the current synaptic weight +static weight_t synapse_structure_get_weight(plastic_synapse_t synaptic_word); + +#endif // _SYNAPSE_STRUCTURE_H_ diff --git a/neural_modelling/src/meanfield_fixing/plasticity/stdp/synapse_structure/synapse_structure_weight_accumulator_impl.h b/neural_modelling/src/meanfield_fixing/plasticity/stdp/synapse_structure/synapse_structure_weight_accumulator_impl.h new file mode 100644 index 00000000000..023a95109c5 --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/plasticity/stdp/synapse_structure/synapse_structure_weight_accumulator_impl.h @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Synapses made of weight and accumulator +#ifndef _SYNAPSE_STRUCUTRE_WEIGHT_STATE_ACCUMULATOR_IMPL_H_ +#define _SYNAPSE_STRUCUTRE_WEIGHT_STATE_ACCUMULATOR_IMPL_H_ + +//--------------------------------------- +// Structures +//--------------------------------------- +//! Plastic synapse contains normal 16-bit weight and an accumulator +typedef struct plastic_synapse_t { + //! The state + weight_t weight; + //! The accumulator + int16_t accumulator; +} plastic_synapse_t; + +//! The update state is a weight state with 32-bit ARM-friendly version of the +//! accumulator +typedef struct update_state_t { + //! The weight staet + weight_state_t weight_state; + //! The accumulator (in ARM-friendly format) + int32_t accumulator; +} update_state_t; + +//! Final states are actually directly what is stored +typedef plastic_synapse_t final_state_t; + +#include "synapse_structure.h" + +//! \brief Get the update state from the synapse structure +//! \param[in] synaptic_word: The plastic synapse data +//! \param[in] synapse_type: What (supported) type of synapse is this? +//! \return The update state +//! \details +//! Creates the update state, using weight-dependence to initialise the +//! weight state, and copying other parameters from the synaptic word into +//! 32-bit form. +static inline update_state_t synapse_structure_get_update_state( + plastic_synapse_t synaptic_word, index_t synapse_type) { + update_state_t update_state; + update_state.weight_state = + weight_get_initial(synaptic_word.weight, synapse_type); + update_state.accumulator = (int32_t) synaptic_word.accumulator; + return update_state; +} + +//--------------------------------------- +//! \brief Get the final state from the update state. +//! \param[in] state: the update state +//! \return the final state +static inline final_state_t synapse_structure_get_final_state( + update_state_t state) { + // Get weight from state + weight_t weight = weight_get_final(state.weight_state); + + // Build this into synaptic word along with updated accumulator and state + return (final_state_t) { + .weight = weight, + .accumulator = (int16_t) state.accumulator + }; +} + +//--------------------------------------- +//! \brief Get the final weight from the final state +//! \param[in] final_state: the final state +//! \return the final weight +static inline weight_t synapse_structure_get_final_weight( + final_state_t final_state) { + return final_state.weight; +} + +//--------------------------------------- +//! \brief Get the final plastic synapse data from the final state +//! \param[in] final_state: the final state +//! \return the final plastic synapse data, ready to be stored +static inline plastic_synapse_t synapse_structure_get_final_synaptic_word( + final_state_t final_state) { + return final_state; +} + +//--------------------------------------- +//! \brief Create the initial plastic synapse data +//! \param[in] weight: the initial synaptic weight +//! \return the plastic synapse data +static inline plastic_synapse_t synapse_structure_create_synapse( + weight_t weight) { + return (plastic_synapse_t) { + .weight = weight, + .accumulator = 0 + }; +} + +//--------------------------------------- +//! \brief Get the current synaptic weight from the plastic synapse data +//! \param[in] synaptic_word: the plastic synapse data +//! \return the current synaptic weight +static inline weight_t synapse_structure_get_weight( + plastic_synapse_t synaptic_word) { + return synaptic_word.weight; +} + +#endif // _SYNAPSE_STRUCUTRE_WEIGHT_STATE_ACCUMULATOR_IMPL_H_ diff --git a/neural_modelling/src/meanfield_fixing/plasticity/stdp/synapse_structure/synapse_structure_weight_impl.h b/neural_modelling/src/meanfield_fixing/plasticity/stdp/synapse_structure/synapse_structure_weight_impl.h new file mode 100644 index 00000000000..cc2bd3f0be5 --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/plasticity/stdp/synapse_structure/synapse_structure_weight_impl.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Synapses just hold weight +#ifndef _SYNAPSE_STRUCUTRE_WEIGHT_IMPL_H_ +#define _SYNAPSE_STRUCUTRE_WEIGHT_IMPL_H_ + +//--------------------------------------- +// Structures +//--------------------------------------- +//! Plastic synapse types are just weights; +typedef weight_t plastic_synapse_t; + +//! The update state is purely a weight state +typedef weight_state_t update_state_t; + +// The final state is just a weight as this is +//! Both the weight and the synaptic word +typedef weight_t final_state_t; + +//--------------------------------------- +// Synapse interface functions +//--------------------------------------- +//! \brief Get the update state from the synapse structure +//! \param[in] synaptic_word: The plastic synapse data +//! \param[in] synapse_type: What (supported) type of synapse is this? +//! \return The update state +static inline update_state_t synapse_structure_get_update_state( + plastic_synapse_t synaptic_word, index_t synapse_type) { + return weight_get_initial(synaptic_word, synapse_type); +} + +//--------------------------------------- +//! \brief Get the final state from the update state. +//! \param[in] state: the update state +//! \return the final state +static inline final_state_t synapse_structure_get_final_state( + update_state_t state) { + return weight_get_final(state); +} + +//--------------------------------------- +//! \brief Get the final weight from the final state +//! \param[in] final_state: the final state +//! \return the final weight +static inline weight_t synapse_structure_get_final_weight( + final_state_t final_state) { + return final_state; +} + +//--------------------------------------- +//! \brief Get the final plastic synapse data from the final state +//! \param[in] final_state: the final state +//! \return the final plastic synapse data, ready to be stored +static inline plastic_synapse_t synapse_structure_get_final_synaptic_word( + final_state_t final_state) { + return final_state; +} + +//--------------------------------------- +//! \brief Create the initial plastic synapse data +//! \param[in] weight: the initial synaptic weight +//! \return the plastic synapse data +static inline plastic_synapse_t synapse_structure_create_synapse( + weight_t weight) { + return weight; +} + +//--------------------------------------- +//! \brief Get the current synaptic weight from the plastic synapse data +//! \param[in] synaptic_word: the plastic synapse data +//! \return the current synaptic weight +static inline weight_t synapse_structure_get_weight( + plastic_synapse_t synaptic_word) { + return synaptic_word; +} + +#endif // _SYNAPSE_STRUCUTRE_WEIGHT_IMPL_H_ diff --git a/neural_modelling/src/meanfield_fixing/plasticity/stdp/synapse_structure/synapse_structure_weight_state_accumulator_impl.h b/neural_modelling/src/meanfield_fixing/plasticity/stdp/synapse_structure/synapse_structure_weight_state_accumulator_impl.h new file mode 100644 index 00000000000..09c3bfd0bc6 --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/plasticity/stdp/synapse_structure/synapse_structure_weight_state_accumulator_impl.h @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Synapse made of weight, accumulator, and other state +#ifndef _SYNAPSE_STRUCUTRE_WEIGHT_STATE_ACCUMULATOR_IMPL_H_ +#define _SYNAPSE_STRUCUTRE_WEIGHT_STATE_ACCUMULATOR_IMPL_H_ + +//--------------------------------------- +// Structures +//--------------------------------------- +//! Plastic synapse contains normal 16-bit weight, a small state machine and an +//! accumulator +typedef struct plastic_synapse_t { + weight_t weight; //!< Weight + int8_t accumulator; //!< Accumulator + uint8_t state; //!< State machine state +} plastic_synapse_t; + +//! The update state is a weight state with 32-bit ARM-friendly versions of the +//! accumulator and the state +typedef struct update_state_t { + weight_state_t weight_state; //!< Weight state + int32_t accumulator; //!< Accumulator + int32_t state; //!< State machine state +} update_state_t; + +//! Final states are actually directly what is stored +typedef plastic_synapse_t final_state_t; + +#include "synapse_structure.h" + +//! \brief Get the update state from the synapse structure +//! \param[in] synaptic_word: The plastic synapse data +//! \param[in] synapse_type: What (supported) type of synapse is this? +//! \return The update state +//! \details +//! Creates update state, using weight dependence to initialise the weight +//! state, and copying other parameters from the synaptic word into 32-bit +//! form +static inline update_state_t synapse_structure_get_update_state( + plastic_synapse_t synaptic_word, index_t synapse_type) { + update_state_t update_state = { + .weight_state = weight_get_initial(synaptic_word.weight, synapse_type), + .accumulator = (int32_t) synaptic_word.accumulator, + .state = (uint32_t) synaptic_word.state + }; + return update_state; +} + +//--------------------------------------- +//! \brief Get the final state from the update state. +//! \param[in] state: the update state +//! \return the final state +static inline final_state_t synapse_structure_get_final_state( + update_state_t state) { + // Get weight from state + weight_t weight = weight_get_final(state.weight_state); + + // Build this into synaptic word along with updated accumulator and state + return (final_state_t) { + .weight = weight, + .accumulator = (int8_t) state.accumulator, + .state = (uint8_t) state.state + }; +} + +//--------------------------------------- +//! \brief Get the final weight from the final state +//! \param[in] final_state: the final state +//! \return the final weight +static inline weight_t synapse_structure_get_final_weight( + final_state_t final_state) { + return final_state.weight; +} + +//--------------------------------------- +//! \brief Get the final plastic synapse data from the final state +//! \param[in] final_state: the final state +//! \return the final plastic synapse data, ready to be stored +static inline plastic_synapse_t synapse_structure_get_final_synaptic_word( + final_state_t final_state) { + return final_state; +} + +//--------------------------------------- +//! \brief Create the initial plastic synapse data +//! \param[in] weight: the initial synaptic weight +//! \return the plastic synapse data +static inline plastic_synapse_t synapse_structure_create_synapse( + weight_t weight) { + plastic_synapse_t initial = { + .weight = weight, + .accumulator = 0, + .state = 0 + }; + return initial; +} + +//--------------------------------------- +//! \brief Get the current synaptic weight from the plastic synapse data +//! \param[in] synaptic_word: the plastic synapse data +//! \return the current synaptic weight +static inline weight_t synapse_structure_get_weight( + plastic_synapse_t synaptic_word) { + return synaptic_word.weight; +} + +#endif _SYNAPSE_STRUCUTRE_WEIGHT_STATE_ACCUMULATOR_IMPL_H_ diff --git a/neural_modelling/src/meanfield_fixing/plasticity/stdp/synapse_structure/synapse_structure_weight_state_accumulator_window_impl.h b/neural_modelling/src/meanfield_fixing/plasticity/stdp/synapse_structure/synapse_structure_weight_state_accumulator_window_impl.h new file mode 100644 index 00000000000..d17d8374b70 --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/plasticity/stdp/synapse_structure/synapse_structure_weight_state_accumulator_window_impl.h @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Synapses made of weight, accumulator, other state, and window +#ifndef _SYNAPSE_STRUCTURE_WEIGHT_STATE_ACCUMULATOR_WINDOW_H_ +#define _SYNAPSE_STRUCTURE_WEIGHT_STATE_ACCUMULATOR_WINDOW_H_ + +//! \brief Plastic synapse contains normal 16-bit weight, a small state machine, +//! an accumulator, and the size of the relevance window +typedef struct plastic_synapse_t { + unsigned int weight : 16; //!< The weight + int accumulator : 4; //!< The accumulator + unsigned int state : 2; //!< The state machine state + unsigned int window_length : 10; //!< The window length +} plastic_synapse_t; + +//! The update state is a weight state with 32-bit ARM-friendly versions of the +//! accumulator, state and window length +typedef struct update_state_t { + weight_state_t weight_state; //!< The weight state + + int32_t accumulator; //!< The accumulator + int32_t state; //!< The state machine state + + uint32_t window_length; //!< The window length +} update_state_t; + +//! Final states are actually directly what is stored +typedef plastic_synapse_t final_state_t; + +#include "synapse_structure.h" + +//! \brief Get the update state from the synapse structure +//! \param[in] synaptic_word: The plastic synapse data +//! \param[in] synapse_type: What (supported) type of synapse is this? +//! \return The update state +static inline update_state_t synapse_structure_get_update_state( + plastic_synapse_t synaptic_word, index_t synapse_type) { + // Create update state, using weight dependance to initialise the weight + // state and copying other parameters from the synaptic word into 32-bit + // form + update_state_t update_state; + update_state.weight_state = + weight_get_initial(synaptic_word.weight, synapse_type); + update_state.accumulator = (int32_t) synaptic_word.accumulator; + update_state.state = (uint32_t) synaptic_word.state; + update_state.window_length = (uint32_t) synaptic_word.window_length; + return update_state; +} + +//--------------------------------------- +//! \brief Get the final state from the update state. +//! \param[in] state: the update state +//! \return the final state +static inline final_state_t synapse_structure_get_final_state( + update_state_t state) { + // Get weight from state + weight_t weight = weight_get_final(state.weight_state); + + // Build this into synaptic word along with updated accumulator and state + return (final_state_t) { + .weight = weight, + .accumulator = (int) state.accumulator, + .state = (unsigned int) state.state, + .window_length = (unsigned int)state.window_length + }; +} + +//--------------------------------------- +//! \brief Get the final weight from the final state +//! \param[in] final_state: the final state +//! \return the final weight +static inline weight_t synapse_structure_get_final_weight( + final_state_t final_state) { + return final_state.weight; +} + +//--------------------------------------- +//! \brief Get the final plastic synapse data from the final state +//! \param[in] final_state: the final state +//! \return the final plastic synapse data, ready to be stored +static inline plastic_synapse_t synapse_structure_get_final_synaptic_word( + final_state_t final_state) { + return final_state; +} + +//--------------------------------------- +//! \brief Create the initial plastic synapse data +//! \param[in] weight: the initial synaptic weight +//! \return the plastic synapse data +static inline plastic_synapse_t synapse_structure_create_synapse( + weight_t weight) { + return (plastic_synapse_t) { + .weight = weight, + .accumulator = 0, + .state = 0, + .window_length = 0 + }; +} + +//--------------------------------------- +//! \brief Get the current synaptic weight from the plastic synapse data +//! \param[in] synaptic_word: the plastic synapse data +//! \return the current synaptic weight +static inline weight_t synapse_structure_get_weight( + plastic_synapse_t synaptic_word) { + return synaptic_word.weight; +} + +#endif // _SYNAPSE_STRUCTURE_WEIGHT_STATE_ACCUMULATOR_WINDOW_H_ diff --git a/neural_modelling/src/meanfield_fixing/plasticity/stdp/timing_dependence/my_timing_impl.c b/neural_modelling/src/meanfield_fixing/plasticity/stdp/timing_dependence/my_timing_impl.c new file mode 100644 index 00000000000..43e26628967 --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/plasticity/stdp/timing_dependence/my_timing_impl.c @@ -0,0 +1,32 @@ +#include "my_timing_impl.h" + +// TODO: Describe the layout of the configuration *in SDRAM* +typedef struct my_timing_config { + accum my_potentiation_parameter; + accum my_depression_parameter; +} my_timing_config_t; + +// TODO: Set up any variables here +accum my_potentiation_parameter; +accum my_depression_parameter; + +//--------------------------------------- +// Functions +//--------------------------------------- +address_t timing_initialise(address_t address) { + + log_info("timing_initialise: starting"); + log_info("\tSTDP my timing rule"); + + // TODO: copy parameters from memory + my_timing_config_t *config = (my_timing_config_t *) address; + my_potentiation_parameter = config->my_potentiation_parameter; + my_depression_parameter = config->my_depression_parameter; + + log_info("my potentiation parameter = %k", my_potentiation_parameter); + log_info("my depression parameter = %k", my_depression_parameter); + log_info("timing_initialise: completed successfully"); + + // Return the address after the configuration (word aligned) + return (address_t) (config + 1); +} diff --git a/neural_modelling/src/meanfield_fixing/plasticity/stdp/timing_dependence/my_timing_impl.h b/neural_modelling/src/meanfield_fixing/plasticity/stdp/timing_dependence/my_timing_impl.h new file mode 100644 index 00000000000..639af0d1a77 --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/plasticity/stdp/timing_dependence/my_timing_impl.h @@ -0,0 +1,128 @@ +#ifndef _MY_TIMING_H_ +#define _MY_TIMING_H_ + +// These need to be defined before including any synapse stuff +#define SYNAPSE_TYPE_BITS 1 +#define SYNAPSE_TYPE_COUNT 2 + +// TODO: Add any variables to be stored in the post trace structure +typedef struct post_trace_t { +} post_trace_t; + +// TODO: Add any variables to be stored in the pre trace structure +typedef struct pre_trace_t { +} pre_trace_t; + +// Because spin1_memcpy() is used in various places +#include + +// Include generic plasticity maths functions +#include + +// TODO: Ensure the correct number of weight terms is chosen +#include + +// TODO: Choose the required synapse structure +#include + +#include + +// Include debug header for log_info etc +#include + +// Note the parameters will be external +extern accum my_potentiation_parameter; +extern accum my_depression_parameter; + +//--------------------------------------- +// Timing dependence inline functions +//--------------------------------------- +static inline post_trace_t timing_get_initial_post_trace(void) { + + // TODO: Return the values required + return (post_trace_t) {}; +} + +//--------------------------------------- +static inline post_trace_t timing_add_post_spike( + uint32_t time, uint32_t last_time, post_trace_t last_trace) { + use(&last_time); + use(&last_trace); + + log_debug("\tdelta_time=%u\n", time - last_time); + + // TODO: Perform operations when a new post-spike occurs + + // Return new pre- synaptic event with decayed trace values with energy + // for new spike added + return (post_trace_t) {}; +} + +//--------------------------------------- +static inline pre_trace_t timing_add_pre_spike( + uint32_t time, uint32_t last_time, pre_trace_t last_trace) { + use(&last_time); + use(&last_trace); + + log_debug("\tdelta_time=%u\n", time - last_time); + + // TODO: Perform operations when a new pre-spike occurs + + return (pre_trace_t ) {}; +} + +//--------------------------------------- +static inline update_state_t timing_apply_pre_spike( + uint32_t time, pre_trace_t trace, uint32_t last_pre_time, + pre_trace_t last_pre_trace, uint32_t last_post_time, + post_trace_t last_post_trace, update_state_t previous_state) { + use(&trace); + use(&last_pre_time); + use(&last_pre_trace); + use(&last_post_trace); + + // TODO: Perform depression on pre spikes that occur after the + // current spike + accum time_since_last_post = (accum) (time - last_post_time); + if (time_since_last_post > 0) { + int32_t decayed_o1 = (int32_t) + (time_since_last_post * my_depression_parameter); + + log_debug("\t\t\ttime_since_last_post=%k, decayed_o1=%d\n", + time_since_last_post, decayed_o1); + + // Apply depression to state (which is a weight_state) + return weight_one_term_apply_depression(previous_state, decayed_o1); + } else { + return previous_state; + } +} + +//--------------------------------------- +static inline update_state_t timing_apply_post_spike( + uint32_t time, post_trace_t trace, uint32_t last_pre_time, + pre_trace_t last_pre_trace, uint32_t last_post_time, + post_trace_t last_post_trace, update_state_t previous_state) { + use(&trace); + use(&last_pre_trace); + use(&last_post_time); + use(&last_post_trace); + + // TODO: Perform potentiation on post spikes that occur after the + // current spike + accum time_since_last_pre = (accum) (time - last_pre_time); + if (time_since_last_pre > 0) { + int32_t decayed_r1 = (int32_t) + (time_since_last_pre * my_potentiation_parameter); + + log_debug("\t\t\ttime_since_last_pre=%k, decayed_r1=%d\n", + time_since_last_pre, decayed_r1); + + // Apply potentiation to state (which is a weight_state) + return weight_one_term_apply_potentiation(previous_state, decayed_r1); + } else { + return previous_state; + } +} + +#endif // _MY_TIMING_H_ diff --git a/neural_modelling/src/meanfield_fixing/plasticity/stdp/timing_dependence/timing.h b/neural_modelling/src/meanfield_fixing/plasticity/stdp/timing_dependence/timing.h new file mode 100644 index 00000000000..e04e472c56f --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/plasticity/stdp/timing_dependence/timing.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \dir +//! \brief STDP timing dependence rules +//! \file +//! \brief API for timing rules +#ifndef _TIMING_H_ +#define _TIMING_H_ + +#include + +//! \brief Initialise the timing dependence state (global) from SDRAM +//! \param[in] address: Location in SDRAM of timing data +//! \return address of first word after the timing data +address_t timing_initialise(address_t address); + +//! \brief Get an initial post-synaptic timing trace +//! \return the post trace +static post_trace_t timing_get_initial_post_trace(void); + +//! \brief Add a post spike to the post trace +//! \param[in] time: the time of the spike +//! \param[in] last_time: the time of the previous spike update +//! \param[in] last_trace: the post trace to update +//! \return the updated post trace +static post_trace_t timing_add_post_spike( + uint32_t time, uint32_t last_time, post_trace_t last_trace); + +//! \brief Add a pre spike to the pre trace +//! \param[in] time: the time of the spike +//! \param[in] last_time: the time of the previous spike update +//! \param[in] last_trace: the pre trace to update +//! \return the updated pre trace +static pre_trace_t timing_add_pre_spike( + uint32_t time, uint32_t last_time, pre_trace_t last_trace); + +//! \brief Apply a pre-spike timing rule state update +//! \param[in] time: the current time +//! \param[in] trace: the current pre-spike trace +//! \param[in] last_pre_time: the time of the last pre-spike +//! \param[in] last_pre_trace: the trace of the last pre-spike +//! \param[in] last_post_time: the time of the last post-spike +//! \param[in] last_post_trace: the trace of the last post-spike +//! \param[in] previous_state: the state to update +//! \return the updated state +static update_state_t timing_apply_pre_spike( + uint32_t time, pre_trace_t trace, uint32_t last_pre_time, + pre_trace_t last_pre_trace, uint32_t last_post_time, + post_trace_t last_post_trace, update_state_t previous_state); + +//! \brief Apply a post-spike timing rule state update +//! \param[in] time: the current time +//! \param[in] trace: the current post-spike trace +//! \param[in] last_pre_time: the time of the last pre-spike +//! \param[in] last_pre_trace: the trace of the last pre-spike +//! \param[in] last_post_time: the time of the last post-spike +//! \param[in] last_post_trace: the trace of the last post-spike +//! \param[in] previous_state: the state to update +//! \return the updated state +static update_state_t timing_apply_post_spike( + uint32_t time, post_trace_t trace, uint32_t last_pre_time, + pre_trace_t last_pre_trace, uint32_t last_post_time, + post_trace_t last_post_trace, update_state_t previous_state); + +#endif // _TIMING_H_ diff --git a/neural_modelling/src/meanfield_fixing/plasticity/stdp/timing_dependence/timing_nearest_pair_impl.h b/neural_modelling/src/meanfield_fixing/plasticity/stdp/timing_dependence/timing_nearest_pair_impl.h new file mode 100644 index 00000000000..1ce07027cc1 --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/plasticity/stdp/timing_dependence/timing_nearest_pair_impl.h @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Timing rule using msot recent spike pair +#ifndef _TIMING_NEAREST_PAIR_IMPL_H_ +#define _TIMING_NEAREST_PAIR_IMPL_H_ + +//--------------------------------------- +// Structures +//--------------------------------------- +typedef struct post_trace_t { +} post_trace_t; + +typedef struct pre_trace_t { +} pre_trace_t; + +#include +#include "timing.h" +#include + +// Include debug header for log_info etc +#include + +// Include generic plasticity maths functions +#include + +//--------------------------------------- +// Timing dependence inline functions +//--------------------------------------- +//! \brief Get an initial post-synaptic timing trace +//! \return the post trace +static inline post_trace_t timing_get_initial_post_trace(void) { + return (post_trace_t) {}; +} + +//--------------------------------------- +//! \brief Add a post spike to the post trace +//! \param[in] time: the time of the spike +//! \param[in] last_time: the time of the previous spike update +//! \param[in] last_trace: the post trace to update +//! \return the updated post trace +static inline post_trace_t timing_add_post_spike( + uint32_t time, uint32_t last_time, UNUSED post_trace_t last_trace) { + log_debug("\tdelta_time=%u\n", time - last_time); + + // Return new pre- synaptic event with decayed trace values with energy + // for new spike added + return (post_trace_t) {}; +} + +//--------------------------------------- +//! \brief Add a pre spike to the pre trace +//! \param[in] time: the time of the spike +//! \param[in] last_time: the time of the previous spike update +//! \param[in] last_trace: the pre trace to update +//! \return the updated pre trace +static inline pre_trace_t timing_add_pre_spike( + uint32_t time, uint32_t last_time, UNUSED pre_trace_t last_trace) { + log_debug("\tdelta_time=%u\n", time - last_time); + + return (pre_trace_t ) {}; +} + +//--------------------------------------- +//! \brief Apply a pre-spike timing rule state update +//! \param[in] time: the current time +//! \param[in] trace: the current pre-spike trace +//! \param[in] last_pre_time: the time of the last pre-spike +//! \param[in] last_pre_trace: the trace of the last pre-spike +//! \param[in] last_post_time: the time of the last post-spike +//! \param[in] last_post_trace: the trace of the last post-spike +//! \param[in] previous_state: the state to update +//! \return the updated state +static inline update_state_t timing_apply_pre_spike( + uint32_t time, UNUSED pre_trace_t trace, UNUSED uint32_t last_pre_time, + UNUSED pre_trace_t last_pre_trace, uint32_t last_post_time, + UNUSED post_trace_t last_post_trace, update_state_t previous_state) { + extern int16_lut *tau_minus_lookup; + + // Get time of event relative to last post-synaptic event + uint32_t time_since_last_post = time - last_post_time; + int32_t decayed_o1 = maths_lut_exponential_decay( + time_since_last_post, tau_minus_lookup); + + log_debug("\t\t\ttime_since_last_post=%u, decayed_o1=%d\n", + time_since_last_post, decayed_o1); + + // Apply depression to state (which is a weight_state) + return weight_one_term_apply_depression(previous_state, decayed_o1); +} + +//--------------------------------------- +//! \brief Apply a post-spike timing rule state update +//! \param[in] time: the current time +//! \param[in] trace: the current post-spike trace +//! \param[in] last_pre_time: the time of the last pre-spike +//! \param[in] last_pre_trace: the trace of the last pre-spike +//! \param[in] last_post_time: the time of the last post-spike +//! \param[in] last_post_trace: the trace of the last post-spike +//! \param[in] previous_state: the state to update +//! \return the updated state +static inline update_state_t timing_apply_post_spike( + uint32_t time, UNUSED post_trace_t trace, uint32_t last_pre_time, + UNUSED pre_trace_t last_pre_trace, uint32_t last_post_time, + UNUSED post_trace_t last_post_trace, update_state_t previous_state) { + extern int16_lut *tau_plus_lookup; + + // Get time of event relative to last pre-synaptic event + uint32_t time_since_last_pre = time - last_pre_time; + uint32_t time_since_last_post = time - last_post_time; + + if (time_since_last_pre > 0) { + int32_t decayed_r1 = maths_lut_exponential_decay( + time_since_last_pre, tau_plus_lookup); + + log_debug("\t\t\ttime_since_last_pret=%u, decayed_r1=%d\n", + time_since_last_pre, decayed_r1); + log_debug("\t\t\ttime_since_last_post=%u, decayed_r1=%d\n", + time_since_last_post, decayed_r1); + + if (time_since_last_post < time_since_last_pre) { + log_debug("\t\t\tSetting trace to zero as not first pre-post pairing"); + decayed_r1 = 0; + } + + // Apply potentiation to state (which is a weight_state) + return weight_one_term_apply_potentiation(previous_state, decayed_r1); + } else { + return previous_state; + } +} + +#endif // _TIMING_NEAREST_PAIR_IMPL_H_ diff --git a/neural_modelling/src/meanfield_fixing/plasticity/stdp/weight_dependence/my_weight_impl.c b/neural_modelling/src/meanfield_fixing/plasticity/stdp/weight_dependence/my_weight_impl.c new file mode 100644 index 00000000000..dfe6eb4293e --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/plasticity/stdp/weight_dependence/my_weight_impl.c @@ -0,0 +1,36 @@ +#include "my_weight_impl.h" + +// Global plasticity parameter data +plasticity_weight_region_data_t *plasticity_weight_region_data; + +address_t weight_initialise( + address_t address, uint32_t n_synapse_types, + uint32_t *ring_buffer_to_input_buffer_left_shifts) { + + // This can be used to indicate the scaling used on the weights + use(ring_buffer_to_input_buffer_left_shifts); + + log_info("weight_initialise: starting"); + log_info("\tSTDP my weight dependence"); + + // Copy plasticity parameter data from address; same format in both + plasticity_weight_region_data = (plasticity_weight_region_data_t *) + spin1_malloc(n_synapse_types * sizeof(plasticity_weight_region_data_t)); + if (plasticity_weight_region_data == NULL) { + log_error("Error allocating plasticity weight data"); + return NULL; + } + plasticity_weight_region_data_t *config = + (plasticity_weight_region_data_t *) address; + for (uint32_t s = 0; s < n_synapse_types; s++) { + plasticity_weight_region_data[s].min_weight = config[s].min_weight; + plasticity_weight_region_data[s].max_weight = config[s].max_weight; + plasticity_weight_region_data[s].my_parameter = config[s].my_parameter; + + // TODO: Copy any other data + } + log_info("weight_initialise: completed successfully"); + + // Return end address of region + return (address_t) &config[n_synapse_types]; +} diff --git a/neural_modelling/src/meanfield_fixing/plasticity/stdp/weight_dependence/my_weight_impl.h b/neural_modelling/src/meanfield_fixing/plasticity/stdp/weight_dependence/my_weight_impl.h new file mode 100644 index 00000000000..c46470b94dc --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/plasticity/stdp/weight_dependence/my_weight_impl.h @@ -0,0 +1,108 @@ +#ifndef _MY_WEIGHT_H_ +#define _MY_WEIGHT_H_ + +// Because spin1_memcpy() is used in various places +#include + +// Include generic plasticity maths functions +#include +#include +#include + +#include + +// A structure for the variables +typedef struct { + int32_t min_weight; + int32_t max_weight; + + int32_t my_parameter; + + // TODO: Put in all required parameters + +} plasticity_weight_region_data_t; + +// An intermediate data structure; can have more accuracy and use more storage +// than the variable structure e.g. weight might be 16-bit but stored as 32-bit +// here +typedef struct { + int32_t initial_weight; + + int32_t potentiation; + int32_t depression; + + const plasticity_weight_region_data_t *weight_region; + + // TODO: Put in any variables required in the intermediate state +} weight_state_t; + +// TODO: Ensure this includes and implements the correct interface +#include + +// The external variables of the weight rule +extern plasticity_weight_region_data_t *plasticity_weight_region_data; + +//--------------------------------------- +// STDP weight dependence functions +//--------------------------------------- +static inline weight_state_t weight_get_initial( + weight_t weight, index_t synapse_type) { + + // TODO: Store the data in the intermediate data structure + return (weight_state_t ) { + .initial_weight = (int32_t) weight, + .potentiation = 0, + .depression = 0, + .weight_region = &plasticity_weight_region_data[synapse_type] + }; +} + +//--------------------------------------- +static inline weight_state_t weight_one_term_apply_depression( + weight_state_t state, int32_t depression) { + + // TODO: Perform intermediate operations in relation to depression + // Note: Can save up to perform complex operations until the end + state.depression += depression; + return state; +} + +//--------------------------------------- +static inline weight_state_t weight_one_term_apply_potentiation( + weight_state_t state, int32_t potentiation) { + + // TODO: Perform intermediate operations in relation to potentiation + // Note: Can save up to perform complex operations until the end + state.potentiation += potentiation; + return state; +} + +//--------------------------------------- +static inline weight_t weight_get_final(weight_state_t new_state) { + + // TODO: Perform operations to get the final weight from the intermediate + // state, taking into account all potentiation and depression + // Note: it is recommended to do a single complex operation here rather + // than one for each potentiation or depression if possible + + int32_t potentiation = + new_state.potentiation * new_state.weight_region->my_parameter; + int32_t depression = + new_state.depression * new_state.weight_region->my_parameter; + + int32_t new_weight = new_state.initial_weight + potentiation - depression; + + // Clamp new weight + new_weight = MIN( + new_state.weight_region->max_weight, + MAX(new_weight, new_state.weight_region->min_weight)); + + log_debug("old_weight:%u, potentiation:%d, depression:%d, " + "scaled potentiation:%d, scaled depression:%d, new_weight:%d", + new_state.initial_weight, new_state.potentiation, + new_state.depression, potentiation, depression, new_weight); + + return (weight_t) new_weight; +} + +#endif // _MY_WEIGHT_H_ diff --git a/neural_modelling/src/meanfield_fixing/plasticity/stdp/weight_dependence/weight.h b/neural_modelling/src/meanfield_fixing/plasticity/stdp/weight_dependence/weight.h new file mode 100644 index 00000000000..d8cb54d2b29 --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/plasticity/stdp/weight_dependence/weight.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/*! + * \dir + * \brief STDP weight dependence rules + * \file + * \brief interface for different weight implementations for the weight half of + * a STDP rule. + * + * \details the API interface contains: + * - weight_initialise(): + * Initialises the weight aspect of a STDP rule. + * - weight_get_initial(): + * Converts the stored weight into an update-able form. + * - weight_get_final(): + * Converts the updated weight into store-able form. + */ + +#ifndef _WEIGHT_H_ +#define _WEIGHT_H_ + +#include +#include + +/*! + * \brief Initialises the weight aspect of an STDP rule. + * \param[in] address: the absolute address in SRAM where the weight parameters + * are stored. + * \param[in] n_synapse_types: The number of synapse types + * \param[in] ring_buffer_to_input_buffer_left_shifts: how much a value needs + * to be shifted in the left direction to support comprises with fixed + * point arithmetic + * \return the end of the weight region as an absolute SDRAM memory address. + */ +address_t weight_initialise( + address_t address, uint32_t n_synapse_types, + uint32_t *ring_buffer_to_input_buffer_left_shifts); + +/*! + * \brief Gets the initial weight state. + * \param[in] weight: The weight at the start + * \param[in] synapse_type: The type of synapse involved + * \return The initial weight state. + */ +static weight_state_t weight_get_initial(weight_t weight, index_t synapse_type); + +/*! + * \brief Gets the final weight. + * \param[in] new_state: The updated weight state + * \return The new weight. + */ +static weight_t weight_get_final(weight_state_t new_state); + +#endif // _WEIGHT_H_ diff --git a/neural_modelling/src/meanfield_fixing/plasticity/stdp/weight_dependence/weight_additive_one_term_impl.c b/neural_modelling/src/meanfield_fixing/plasticity/stdp/weight_dependence/weight_additive_one_term_impl.c new file mode 100644 index 00000000000..f0dbf524f1e --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/plasticity/stdp/weight_dependence/weight_additive_one_term_impl.c @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Support code for weight_additive_one_term_impl.h +#include "weight_additive_one_term_impl.h" + +//--------------------------------------- +// Globals +//--------------------------------------- +//! Global plasticity parameter data +plasticity_weight_region_data_t *plasticity_weight_region_data; + +//! \brief How the configuration data for additive_one_term is laid out in +//! SDRAM. The layout is an array of these. +typedef struct { + int32_t min_weight; + int32_t max_weight; + int32_t a2_plus; + int32_t a2_minus; +} additive_one_term_config_t; + +//--------------------------------------- +// Functions +//--------------------------------------- +address_t weight_initialise( + address_t address, uint32_t n_synapse_types, + UNUSED uint32_t *ring_buffer_to_input_buffer_left_shifts) { + log_debug("weight_initialise: starting"); + log_debug("\tSTDP additive one-term weight dependence"); + + // Copy plasticity region data from address + // **NOTE** this seems somewhat safer than relying on sizeof + additive_one_term_config_t *config = (additive_one_term_config_t *) address; + + plasticity_weight_region_data_t *dtcm_copy = plasticity_weight_region_data = + spin1_malloc(sizeof(plasticity_weight_region_data_t) * n_synapse_types); + if (dtcm_copy == NULL) { + log_error("Could not initialise weight region data"); + return NULL; + } + for (uint32_t s = 0; s < n_synapse_types; s++, config++) { + dtcm_copy[s].min_weight = config->min_weight; + dtcm_copy[s].max_weight = config->max_weight; + dtcm_copy[s].a2_plus = config->a2_plus; + dtcm_copy[s].a2_minus = config->a2_minus; + + log_debug("\tSynapse type %u: Min weight:%d, Max weight:%d, A2+:%d, A2-:%d", + s, dtcm_copy[s].min_weight, dtcm_copy[s].max_weight, + dtcm_copy[s].a2_plus, dtcm_copy[s].a2_minus); + } + log_debug("weight_initialise: completed successfully"); + + // Return end address of region + return (address_t) config; +} diff --git a/neural_modelling/src/meanfield_fixing/plasticity/stdp/weight_dependence/weight_additive_one_term_impl.h b/neural_modelling/src/meanfield_fixing/plasticity/stdp/weight_dependence/weight_additive_one_term_impl.h new file mode 100644 index 00000000000..1de7a96221d --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/plasticity/stdp/weight_dependence/weight_additive_one_term_impl.h @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Additive single-term weight dependence rule +#ifndef _WEIGHT_ADDITIVE_ONE_TERM_IMPL_H_ +#define _WEIGHT_ADDITIVE_ONE_TERM_IMPL_H_ + +// Include generic plasticity maths functions +#include +#include +#include + +#include + +//--------------------------------------- +// Structures +//--------------------------------------- +//! The configuration of the rule +typedef struct { + int32_t min_weight; //!< Minimum weight + int32_t max_weight; //!< Maximum weight + + int32_t a2_plus; //!< Scaling factor for weight delta on potentiation + int32_t a2_minus; //!< Scaling factor for weight delta on depression +} plasticity_weight_region_data_t; + +//! The current state data for the rule +typedef struct { + int32_t initial_weight; //!< The starting weight + + int32_t a2_plus; //!< Cumulative potentiation delta + int32_t a2_minus; //!< Cumulative depression delta + + //! Reference to the configuration data + const plasticity_weight_region_data_t *weight_region; +} weight_state_t; + +#include "weight_one_term.h" + +//--------------------------------------- +// STDP weight dependence functions +//--------------------------------------- +/*! + * \brief Gets the initial weight state. + * \param[in] weight: The weight at the start + * \param[in] synapse_type: The type of synapse involved + * \return The initial weight state. + */ +static inline weight_state_t weight_get_initial( + weight_t weight, index_t synapse_type) { + extern plasticity_weight_region_data_t *plasticity_weight_region_data; + + return (weight_state_t) { + .initial_weight = (int32_t) weight, + .a2_plus = 0, + .a2_minus = 0, + .weight_region = &plasticity_weight_region_data[synapse_type] + }; +} + +//--------------------------------------- +//! \brief Apply the depression rule to the weight state +//! \param[in] state: The weight state to update +//! \param[in] a2_minus: The amount of depression to apply +//! \return the updated weight state +static inline weight_state_t weight_one_term_apply_depression( + weight_state_t state, int32_t a2_minus) { + state.a2_minus += a2_minus; + return state; +} + +//--------------------------------------- +//! \brief Apply the potentiation rule to the weight state +//! \param[in] state: The weight state to update +//! \param[in] a2_plus: The amount of potentiation to apply +//! \return the updated weight state +static inline weight_state_t weight_one_term_apply_potentiation( + weight_state_t state, int32_t a2_plus) { + state.a2_plus += a2_plus; + return state; +} + +//--------------------------------------- +/*! + * \brief Gets the final weight. + * \param[in] new_state: The updated weight state + * \return The new weight. + */ +static inline weight_t weight_get_final(weight_state_t new_state) { + // Scale potentiation and depression + // **NOTE** A2+ and A2- are pre-scaled into weight format + int32_t scaled_a2_plus = STDP_FIXED_MUL_16X16( + new_state.a2_plus, new_state.weight_region->a2_plus); + int32_t scaled_a2_minus = STDP_FIXED_MUL_16X16( + new_state.a2_minus, new_state.weight_region->a2_minus); + + // Apply all terms to initial weight + int32_t new_weight = + new_state.initial_weight + scaled_a2_plus - scaled_a2_minus; + + // Clamp new weight + new_weight = MIN(new_state.weight_region->max_weight, + MAX(new_weight, new_state.weight_region->min_weight)); + + log_debug("\told_weight:%u, a2+:%d, a2-:%d, scaled a2+:%d, scaled a2-:%d," + " new_weight:%d", + new_state.initial_weight, new_state.a2_plus, new_state.a2_minus, + scaled_a2_plus, scaled_a2_minus, new_weight); + + return (weight_t) new_weight; +} + +#endif // _WEIGHT_ADDITIVE_ONE_TERM_IMPL_H_ diff --git a/neural_modelling/src/meanfield_fixing/plasticity/stdp/weight_dependence/weight_one_term.h b/neural_modelling/src/meanfield_fixing/plasticity/stdp/weight_dependence/weight_one_term.h new file mode 100644 index 00000000000..b4f369dd657 --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/plasticity/stdp/weight_dependence/weight_one_term.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief API for single-term weight dependence rules +#ifndef _WEIGHT_ONE_TERM_H_ +#define _WEIGHT_ONE_TERM_H_ + +#include "weight.h" + +//! \brief Apply the depression rule to the weight state +//! \param[in] state: The weight state to update +//! \param[in] depression: The amount of depression to apply +//! \return the updated weight state +static weight_state_t weight_one_term_apply_depression( + weight_state_t state, int32_t depression); + +//! \brief Apply the potentiation rule to the weight state +//! \param[in] state: The weight state to update +//! \param[in] potentiation: The amount of potentiation to apply +//! \return the updated weight state +static weight_state_t weight_one_term_apply_potentiation( + weight_state_t state, int32_t potentiation); + +#endif // _WEIGHT_ONE_TERM_H_ diff --git a/neural_modelling/src/meanfield_fixing/plasticity/synapse_dynamics.h b/neural_modelling/src/meanfield_fixing/plasticity/synapse_dynamics.h new file mode 100644 index 00000000000..e2e9495ab98 --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/plasticity/synapse_dynamics.h @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \dir +//! \brief Dynamic synapses +//! \file +//! \brief API for synapse dynamics +#ifndef _SYNAPSE_DYNAMICS_H_ +#define _SYNAPSE_DYNAMICS_H_ + +#include +#include + +//! \brief Initialise the synapse dynamics +//! \param[in] address: Where the configuration data is +//! \param[in] n_neurons: Number of neurons +//! \param[in] n_synapse_types: Number of synapse types +//! \param[in] ring_buffer_to_input_buffer_left_shifts: +//! How to interpret the values from the ring buffers +//! \return Whether the initialisation succeeded. +bool synapse_dynamics_initialise( + address_t address, uint32_t n_neurons, uint32_t n_synapse_types, + uint32_t *ring_buffer_to_input_buffer_left_shifts); + +//! \brief Process the dynamics of the synapses +//! \param[in,out] plastic_region_data: Where the plastic data is +//! \param[in] fixed_region: Where the fixed data is +//! \param[in,out] ring_buffers: The ring buffers +//! \param[in] time: The current simulation time +//! \return ??? +bool synapse_dynamics_process_plastic_synapses( + synapse_row_plastic_data_t *plastic_region_data, + synapse_row_fixed_part_t *fixed_region, + weight_t *ring_buffers, uint32_t time); + +//! \brief Inform the synapses that the neuron fired +//! \param[in] time: The current simulation time +//! \param[in] neuron_index: Which neuron are we processing +void synapse_dynamics_process_post_synaptic_event( + uint32_t time, index_t neuron_index); + +//! \brief Get the intrinsic bias of the synapses +//! \param[in] time: The current simulation time +//! \param[in] neuron_index: Which neuron are we processing +//! \return The intrinsic bias +input_t synapse_dynamics_get_intrinsic_bias( + uint32_t time, index_t neuron_index); + +//! \brief Print the synapse dynamics +//! \param[in] plastic_region_data: Where the plastic data is +//! \param[in] fixed_region: Where the fixed data is +//! \param[in] ring_buffer_to_input_buffer_left_shifts: +//! How to interpret the values from the ring buffers +void synapse_dynamics_print_plastic_synapses( + synapse_row_plastic_data_t *plastic_region_data, + synapse_row_fixed_part_t *fixed_region, + uint32_t *ring_buffer_to_input_buffer_left_shifts); + +//! \brief Get the counters for plastic pre synaptic events based on (if +//! the model was compiled with SYNAPSE_BENCHMARK parameter) or returns 0 +//! \return counters for plastic pre synaptic events or 0 +uint32_t synapse_dynamics_get_plastic_pre_synaptic_events(void); + +//! \brief Get the number of ring buffer saturation events due to adding +//! plastic weights. +//! \return counter for saturation events or 0 +uint32_t synapse_dynamics_get_plastic_saturation_count(void); + +//----------------------------------------------------------------------------- +// Synaptic rewiring functions +//----------------------------------------------------------------------------- + +//! \brief Search the synaptic row for the the connection with the +//! specified post-synaptic ID +//! \param[in] id: the (core-local) ID of the neuron to search for in the +//! synaptic row +//! \param[in] row: the core-local address of the synaptic row +//! \param[out] weight: address to contain the weight of the connection +//! \param[out] delay: address to contain the delay of the connection +//! \param[out] offset: address to contain the offset of the connection +//! \param[out] synapse_type: the synapse type of the connection +//! \return was the search successful? +bool synapse_dynamics_find_neuron( + uint32_t id, synaptic_row_t row, weight_t *weight, uint16_t *delay, + uint32_t *offset, uint32_t *synapse_type); + +//! \brief Remove the entry at the specified offset in the synaptic row +//! \param[in] offset: the offset in the row at which to remove the entry +//! \param[in] row: the core-local address of the synaptic row +//! \return was the removal successful? +bool synapse_dynamics_remove_neuron(uint32_t offset, synaptic_row_t row); + +//! \brief Add an entry in the synaptic row +//! \param[in] id: the (core-local) ID of the post-synaptic neuron to be added +//! \param[in] row: the core-local address of the synaptic row +//! \param[in] weight: the initial weight associated with the connection +//! \param[in] delay: the delay associated with the connection +//! \param[in] type: the type of the connection (e.g. inhibitory) +//! \return was the addition successful? +bool synapse_dynamics_add_neuron( + uint32_t id, synaptic_row_t row, weight_t weight, + uint32_t delay, uint32_t type); + +//! \brief Get the number of connections in the given row +//! \param[in] fixed: the fixed region of the synaptic row +//! \return The number of connections in the row +uint32_t synapse_dynamics_n_connections_in_row(synapse_row_fixed_part_t *fixed); + +#endif // _SYNAPSE_DYNAMICS_H_ diff --git a/neural_modelling/src/meanfield_fixing/plasticity/synapse_dynamics_static_impl.c b/neural_modelling/src/meanfield_fixing/plasticity/synapse_dynamics_static_impl.c new file mode 100644 index 00000000000..75eb6a6548a --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/plasticity/synapse_dynamics_static_impl.c @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/*! + * \file + * \brief This file contains the main interface for structural plasticity + * and some shared code. For the main implementation, see topographic_map_impl.c + * + * \author Petrut Bogdan + */ +#include "synapse_dynamics.h" +#include +#include + +//! ::synapse_index_bits + ::synapse_type_bits +static uint32_t synapse_type_index_bits; +//! Number of bits to hold the neuron index +static uint32_t synapse_index_bits; +//! Mask to extract the neuron index (has ::synapse_index_bits bits set) +static uint32_t synapse_index_mask; +//! Number of bits to hold the synapse type +static uint32_t synapse_type_bits; +//! Mask to extract the synapse type (has ::synapse_type_bits bits set) +static uint32_t synapse_type_mask; + +bool synapse_dynamics_initialise( + UNUSED address_t address, uint32_t n_neurons, uint32_t n_synapse_types, + UNUSED uint32_t *ring_buffer_to_input_buffer_left_shifts) { + uint32_t n_neurons_power_2 = n_neurons; + uint32_t log_n_neurons = 1; + if (n_neurons != 1) { + if (!is_power_of_2(n_neurons)) { + n_neurons_power_2 = next_power_of_2(n_neurons); + } + log_n_neurons = ilog_2(n_neurons_power_2); + } + uint32_t n_synapse_types_power_2 = n_synapse_types; + synapse_type_bits = 1; + if (n_synapse_types != 1) { + if (!is_power_of_2(n_synapse_types)) { + n_synapse_types_power_2 = next_power_of_2(n_synapse_types); + } + synapse_type_bits = ilog_2(n_synapse_types_power_2); + } + synapse_type_index_bits = log_n_neurons + synapse_type_bits; + synapse_index_bits = log_n_neurons; + synapse_index_mask = (1 << synapse_index_bits) - 1; + synapse_type_mask = (1 << synapse_type_bits) - 1; + return true; +} + +//--------------------------------------- +void synapse_dynamics_process_post_synaptic_event( + UNUSED uint32_t time, UNUSED index_t neuron_index) { +} + +//--------------------------------------- +bool synapse_dynamics_process_plastic_synapses( + UNUSED synapse_row_plastic_data_t *plastic_region_data, + UNUSED synapse_row_fixed_part_t *fixed_region, + UNUSED weight_t *ring_buffer, UNUSED uint32_t time) { + log_error("There should be no plastic synapses!"); + return false; +} + +//--------------------------------------- +input_t synapse_dynamics_get_intrinsic_bias( + UNUSED uint32_t time, UNUSED index_t neuron_index) { + return ZERO; +} + +void synapse_dynamics_print_plastic_synapses( + UNUSED synapse_row_plastic_data_t *plastic_region_data, + UNUSED synapse_row_fixed_part_t *fixed_region, + UNUSED uint32_t *ring_buffer_to_input_left_shifts) { +} + +uint32_t synapse_dynamics_get_plastic_pre_synaptic_events(void) { + return 0; +} + +uint32_t synapse_dynamics_get_plastic_saturation_count(void) { + return 0; +} + +bool synapse_dynamics_find_neuron( + uint32_t id, synaptic_row_t row, weight_t *weight, uint16_t *delay, + uint32_t *offset, uint32_t *synapse_type) { + synapse_row_fixed_part_t *fixed_region = synapse_row_fixed_region(row); + int32_t fixed_synapse = synapse_row_num_fixed_synapses(fixed_region); + uint32_t *synaptic_words = synapse_row_fixed_weight_controls(fixed_region); + + // Loop through plastic synapses + for (; fixed_synapse > 0; fixed_synapse--) { + + // Get next control word (auto incrementing) + // Check if index is the one I'm looking for + uint32_t synaptic_word = *synaptic_words++; + if (synapse_row_sparse_index(synaptic_word, synapse_index_mask) == id) { + *offset = synapse_row_num_fixed_synapses(fixed_region) - + fixed_synapse; + *weight = synapse_row_sparse_weight(synaptic_word); + *delay = synapse_row_sparse_delay(synaptic_word, + synapse_type_index_bits); + *synapse_type = synapse_row_sparse_type( + synaptic_word, synapse_index_bits, synapse_type_mask); + return true; + } + } + + return false; +} + +bool synapse_dynamics_remove_neuron(uint32_t offset, synaptic_row_t row) { + synapse_row_fixed_part_t *fixed_region = synapse_row_fixed_region(row); + int32_t fixed_synapse = synapse_row_num_fixed_synapses(fixed_region); + uint32_t *synaptic_words = synapse_row_fixed_weight_controls(fixed_region); + + // Delete control word at offset (contains weight) + synaptic_words[offset] = synaptic_words[fixed_synapse - 1]; + + // Decrement FF + fixed_region->num_fixed--; + return true; +} + +//! packing all of the information into the required static control word +static inline uint32_t _fixed_synapse_convert( + uint32_t id, weight_t weight, uint32_t delay, uint32_t type) { + uint32_t new_synapse = weight << (32 - SYNAPSE_WEIGHT_BITS); + new_synapse |= ((delay & ((1 << SYNAPSE_DELAY_BITS) - 1)) << + synapse_type_index_bits); + new_synapse |= ((type & ((1 << synapse_type_bits) - 1)) << + synapse_index_bits); + new_synapse |= (id & ((1 << synapse_type_index_bits) - 1)); + return new_synapse; +} + +bool synapse_dynamics_add_neuron( + uint32_t id, synaptic_row_t row, weight_t weight, + uint32_t delay, uint32_t type) { + synapse_row_fixed_part_t *fixed_region = synapse_row_fixed_region(row); + int32_t fixed_synapse = synapse_row_num_fixed_synapses(fixed_region); + uint32_t *synaptic_words = synapse_row_fixed_weight_controls(fixed_region); + uint32_t new_synapse = _fixed_synapse_convert(id, weight, delay, type); + + // Add control word at offset + synaptic_words[fixed_synapse] = new_synapse; + + // Increment FF + fixed_region->num_fixed++; + return true; +} + +uint32_t synapse_dynamics_n_connections_in_row( + synapse_row_fixed_part_t *fixed) { + return synapse_row_num_fixed_synapses(fixed); +} diff --git a/neural_modelling/src/meanfield_fixing/population_table/population_table.h b/neural_modelling/src/meanfield_fixing/population_table/population_table.h new file mode 100644 index 00000000000..963d03d680e --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/population_table/population_table.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \dir +//! \brief Master population tables +//! \file +//! \brief Master pop(ulation) table API +#ifndef _POPULATION_TABLE_H_ +#define _POPULATION_TABLE_H_ + +#include +#include + +//! \brief the number of times a DMA resulted in 0 entries +extern uint32_t ghost_pop_table_searches; + +//! \brief the number of times packet isn't in the master pop table at all! +extern uint32_t invalid_master_pop_hits; + +//! \brief The number of bit fields which were not able to be read in due to +//! DTCM limits. +extern uint32_t failed_bit_field_reads; + +//! \brief The number of packets dropped because the bitfield filter says +//! they don't hit anything +extern uint32_t bit_field_filtered_packets; + +//! \brief Set up the table +//! \param[in] table_address: The address of the start of the table data +//! \param[in] synapse_rows_address: The address of the start of the synapse +//! data +//! \param[in] direct_rows_address: The address of the start of the direct +//! synapse data +//! \param[out] row_max_n_words: Updated with the maximum length of any row in +//! the table in words +//! \return True if the table was initialised successfully, False otherwise +bool population_table_initialise( + address_t table_address, address_t synapse_rows_address, + address_t direct_rows_address, uint32_t *row_max_n_words); + +//! \brief Initialise the bitfield filtering system. +//! \param[in] filter_region: Where the bitfield configuration is +//! \return True on success +bool population_table_load_bitfields(filter_region_t *filter_region); + +//! \brief Get the first row data for the given input spike +//! \param[in] spike: The spike received +//! \param[out] row_address: Updated with the address of the row +//! \param[out] n_bytes_to_transfer: Updated with the number of bytes to read +//! \return True if there is a row to read, False if not +bool population_table_get_first_address( + spike_t spike, synaptic_row_t* row_address, + size_t* n_bytes_to_transfer); + +//! \brief Get the next row data for a previously given spike. If no spike has +//! been given, return False. +//! \param[out] spike: The initiating spike +//! \param[out] row_address: Updated with the address of the row +//! \param[out] n_bytes_to_transfer: Updated with the number of bytes to read +//! \return True if there is a row to read, False if not +bool population_table_get_next_address( + spike_t *spike, synaptic_row_t* row_address, + size_t* n_bytes_to_transfer); + +#endif // _POPULATION_TABLE_H_ diff --git a/neural_modelling/src/meanfield_fixing/population_table/population_table_binary_search_impl.c b/neural_modelling/src/meanfield_fixing/population_table/population_table_binary_search_impl.c new file mode 100644 index 00000000000..d736a1a9c70 --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/population_table/population_table_binary_search_impl.c @@ -0,0 +1,592 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Master population table implementation that uses binary search +#include "population_table.h" +#include +#include +#include + +//! bits in a word +#define BITS_PER_WORD 32 + +//! \brief The highest bit within the word +#define TOP_BIT_IN_WORD 31 + +//! \brief The flag for when a spike isn't in the master pop table (so +//! shouldn't happen) +#define NOT_IN_MASTER_POP_TABLE_FLAG -1 + +//! \brief The number of bits of address. +//! This is a constant as it is used more than once below. +#define N_ADDRESS_BITS 23 + +//! \brief The shift to apply to indirect addresses. +//! The address is in units of four words, so this multiplies by 16 (= up +//! shifts by 4) +#define INDIRECT_ADDRESS_SHIFT 4 + +//! \brief An entry in the master population table. +typedef struct master_population_table_entry { + //! The key to match against the incoming message + uint32_t key; + //! The mask to select the relevant bits of \p key for matching + uint32_t mask; + //! The index into ::address_list for this entry + uint32_t start: 15; + //! Flag to indicate if an extra_info struct is present + uint32_t extra_info_flag: 1; + //! The number of entries in ::address_list for this entry + uint32_t count: 16; +} master_population_table_entry; + +//! \brief A packed extra info (note: same size as address and row length) +typedef struct extra_info { + //! The mask to apply to the key once shifted get the core index + uint32_t core_mask: 10; + //! The number of words required for n_neurons + uint32_t n_words: 6; + //! The shift to apply to the key to get the core part (0-31) + uint32_t mask_shift: 5; + //! The number of neurons per core (up to 2048) + uint32_t n_neurons: 11; +} extra_info; + +//! \brief A packed address and row length (note: same size as extra info) +typedef struct { + //! the length of the row + uint32_t row_length : 8; + //! the address + uint32_t address : N_ADDRESS_BITS; + //! whether this is a direct/single address + uint32_t is_single : 1; +} address_and_row_length; + +//! \brief An entry in the address list is either an address and row length or extra +//! info if flagged. +typedef union { + address_and_row_length addr; + extra_info extra; +} address_list_entry; + +// An Invalid address and row length; used to keep indices aligned between +// delayed and undelayed tables +#define INVALID_ADDRESS ((1 << N_ADDRESS_BITS) - 1) + +//! \brief The memory layout in SDRAM of the first part of the population table +//! configuration. Address list data (array of ::address_and_row_length) is +//! packed on the end. +typedef struct { + uint32_t table_length; + uint32_t addr_list_length; + master_population_table_entry data[]; +} pop_table_config_t; + +//! The master population table. This is sorted. +static master_population_table_entry *master_population_table; + +//! The length of ::master_population_table +static uint32_t master_population_table_length; + +//! The array of information that points into the synaptic matrix +static address_list_entry *address_list; + +//! Base address for the synaptic matrix's indirect rows +static uint32_t synaptic_rows_base_address; + +//! Base address for the synaptic matrix's direct rows +static uint32_t direct_rows_base_address; + +//! \brief The last spike received +static spike_t last_spike = 0; + +//! \brief The last neuron id for the key +static uint32_t last_neuron_id = 0; + +//! the index for the next item in the ::address_list +static uint16_t next_item = 0; + +//! The number of relevant items remaining in the ::address_list +static uint16_t items_to_go = 0; + +//! The bitfield map +static bit_field_t *connectivity_bit_field = NULL; + +//! \brief the number of times a DMA resulted in 0 entries +uint32_t ghost_pop_table_searches = 0; + +//! \brief the number of times packet isnt in the master pop table at all! +uint32_t invalid_master_pop_hits = 0; + +//! \brief The number of bit fields which were not able to be read in due to +//! DTCM limits. +uint32_t failed_bit_field_reads = 0; + +//! \brief The number of packets dropped because the bitfield filter says +//! they don't hit anything +uint32_t bit_field_filtered_packets = 0; + +//! \name Support functions +//! \{ + +//! \brief Get the direct row address out of an entry +//! \param[in] entry: the table entry +//! \return a direct row address +static inline uint32_t get_direct_address(address_and_row_length entry) { + return entry.address + direct_rows_base_address; +} + +//! \brief Get the standard address offset out of an entry +//! \details The address is in units of four words, so this multiplies by 16 +//! (= up shifts by 4) +//! \param[in] entry: the table entry +//! \return a row address (which is an offset) +static inline uint32_t get_offset(address_and_row_length entry) { + return entry.address << INDIRECT_ADDRESS_SHIFT; +} + +//! \brief Get the standard address out of an entry +//! \param[in] entry: the table entry +//! \return a row address +static inline uint32_t get_address(address_and_row_length entry) { + return get_offset(entry) + synaptic_rows_base_address; +} + +//! \brief Get the length of the row from the entry +//! +//! Row lengths are stored offset by 1, to allow 1-256 length rows +//! +//! \param[in] entry: the table entry +//! \return the row length +static inline uint32_t get_row_length(address_and_row_length entry) { + return entry.row_length + 1; +} + +//! \brief Get the source core index from a spike +//! \param[in] extra: The extra info entry +//! \param[in] spike: The spike received +//! \return the source core index in the list of source cores +static inline uint32_t get_core_index(extra_info extra, spike_t spike) { + return (spike >> extra.mask_shift) & extra.core_mask; +} + +//! \brief Get the total number of neurons on cores which come before this core +//! \param[in] extra: The extra info entry +//! \param[in] spike: The spike received +//! \return the base neuron number of this core +static inline uint32_t get_core_sum(extra_info extra, spike_t spike) { + return get_core_index(extra, spike) * extra.n_neurons; +} + +//! \brief Get the total number of bits in bitfields for cores which came before +//! this core. +//! \param[in] extra: The extra info entry +//! \param[in] spike: The spike received +//! \return the base bitfield bit index of this core +static inline uint32_t get_bitfield_sum(extra_info extra, spike_t spike) { + return get_core_index(extra, spike) * extra.n_words * BITS_PER_WORD; +} + +//! \brief Get the source neuron ID for a spike given its table entry (without extra info) +//! \param[in] entry: the table entry +//! \param[in] spike: the spike +//! \return the neuron ID +static inline uint32_t get_neuron_id( + master_population_table_entry entry, spike_t spike) { + return spike & ~entry.mask; +} + +//! \brief Get the neuron id of the neuron on the source core, for a spike with +// extra info +//! \param[in] entry: the table entry +//! \param[in] extra_info: the extra info entry +//! \param[in] spike: the spike received +//! \return the source neuron id local to the core +static inline uint32_t get_local_neuron_id( + master_population_table_entry entry, extra_info extra, spike_t spike) { + return spike & ~(entry.mask | (extra.core_mask << extra.mask_shift)); +} + +//! \brief Prints the master pop table. +//! \details For debugging +static inline void print_master_population_table(void) { +#if log_level >= LOG_DEBUG + log_info("Master_population\n"); + for (uint32_t i = 0; i < master_population_table_length; i++) { + master_population_table_entry entry = master_population_table[i]; + log_info("key: 0x%08x, mask: 0x%08x", entry.key, entry.mask); + int count = entry.count; + int start = entry.start; + if (entry.extra_info_flag) { + extra_info extra = address_list[start].extra; + start += 1; + log_info(" core_mask: 0x%08x, core_shift: %u, n_neurons: %u, n_words: %u", + extra.core_mask, extra.mask_shift, extra.n_neurons, extra.n_words); + } + for (uint16_t j = start; j < (start + count); j++) { + address_and_row_length addr = address_list[j].addr; + if (addr.address == INVALID_ADDRESS) { + log_info(" index %d: INVALID", j); + } else if (!addr.is_single) { + log_info(" index %d: offset: %u, address: 0x%08x, row_length: %u", + j, get_offset(addr), get_address(addr), get_row_length(addr)); + } else { + log_info(" index %d: offset: %u, address: 0x%08x, single", + j, addr.address, get_direct_address(addr)); + } + } + } + log_info("Population table has %u entries", master_population_table_length); +#endif +} + +//! \brief Check if the entry is a match for the given key +//! \param[in] mp_i: The master population table entry index +//! \param[in] key: The key to check +//! \return: Whether the key matches the entry +static inline bool matches(uint32_t mp_i, uint32_t key) { + return (key & master_population_table[mp_i].mask) == + master_population_table[mp_i].key; +} + +//! \brief Print bitfields for debugging +//! \param[in] mp_i: The master population table entry index +//! \param[in] start: The first index of the bitfield to print +//! \param[in] end: The index after the last bitfield to print +//! \param[in] filters: The bitfields to print +static inline void print_bitfields(uint32_t mp_i, uint32_t start, + uint32_t end, filter_info_t *filters) { +#if LOG_LEVEL >= LOG_DEBUG + // print out the bit field for debug purposes + log_info("Bit field(s) for key 0x%08x:", master_population_table[mp_i].key); + uint32_t offset = 0; + for (uint32_t bf_i = start; bf_i < end; bf_i++) { + uint32_t n_words = get_bit_field_size(filters[bf_i].n_atoms); + for (uint32_t i = 0; i < n_words; i++) { + log_info("0x%08x", connectivity_bit_field[mp_i][offset + i]); + } + offset += n_words; + } +#else + use(mp_i); + use(start); + use(end); + use(filters); +#endif +} + +bool population_table_load_bitfields(filter_region_t *filter_region) { + + if (master_population_table_length == 0) { + return true; + } + // try allocating DTCM for starting array for bitfields + connectivity_bit_field = + spin1_malloc(sizeof(bit_field_t) * master_population_table_length); + if (connectivity_bit_field == NULL) { + log_warning( + "Couldn't initialise basic bit field holder. Will end up doing" + " possibly more DMA's during the execution than required." + " We required %d bytes where %d are available", + sizeof(bit_field_t) * master_population_table_length, + sark_heap_max(sark.heap, 0)); + return true; + } + + // Go through the population table, and the relevant bitfield list, both + // of which are ordered by key... + uint32_t bf_i = 0; + uint32_t n_filters = filter_region->n_filters; + filter_info_t* filters = filter_region->filters; + for (uint32_t mp_i = 0; mp_i < master_population_table_length; mp_i++) { + connectivity_bit_field[mp_i] = NULL; + + log_debug("Master pop key: 0x%08x, mask: 0x%08x", + master_population_table[mp_i].key, master_population_table[mp_i].mask); + +#ifdef LOG_DEBUG + // Sanity checking code; not needed in normal operation, and costs ITCM + // With both things being in key order, this should never happen... + if (bf_i < n_filters && + filters[bf_i].key < master_population_table[mp_i].key) { + log_error("Skipping bitfield %d for key 0x%08x", bf_i, filters[bf_i].key); + rt_error(RTE_SWERR); + } +#endif + + // While there is a match, keep track of the start and end; note this + // may recheck the first entry, but there might not be a first entry if + // we have already gone off the end of the bitfield array + uint32_t start = bf_i; + uint32_t n_words_total = 0; + uint32_t useful = 0; + log_debug("Starting with bit field %d with key 0x%08x", bf_i, filters[bf_i].key); + while (bf_i < n_filters && matches(mp_i, filters[bf_i].key)) { + log_debug("Using bit field %d with key 0x%08x, merged %d, redundant %d", + bf_i, filters[bf_i].key, filters[bf_i].merged, filters[bf_i].all_ones); + n_words_total += get_bit_field_size(filters[bf_i].n_atoms); + useful += !(filters[bf_i].merged || filters[bf_i].all_ones); + bf_i++; + } + + // If there is something to copy, copy them in now + log_debug("Ended with bit field %d with key 0x%08x, n_words %d, useful %d", + bf_i, filters[bf_i].key, n_words_total, useful); + if (bf_i != start && useful) { + // Try to allocate all the bitfields for this entry + connectivity_bit_field[mp_i] = spin1_malloc( + sizeof(bit_field_t) * n_words_total); + if (connectivity_bit_field[mp_i] == NULL) { + // If allocation fails, we can still continue + log_debug( + "Could not initialise bit field for key %d, packets with " + "that key will use a DMA to check if the packet targets " + "anything within this core. Potentially slowing down the " + "execution of neurons on this core.", + master_population_table[mp_i].key); + // There might be more than one that has failed + failed_bit_field_reads += bf_i - start; + } else { + // If allocation succeeds, copy the bitfields in + bit_field_t bf_pointer = &connectivity_bit_field[mp_i][0]; + for (uint32_t i = start; i < bf_i; i++) { + uint32_t n_words = get_bit_field_size(filters[i].n_atoms); + spin1_memcpy(bf_pointer, filters[i].data, n_words * sizeof(uint32_t)); + bf_pointer = &bf_pointer[n_words]; + } + + print_bitfields(mp_i, start, bf_i, filters); + } + } + } + return true; +} + +//! \brief Get the position in the master population table. +//! \param[in] spike: The spike received +//! \param[out] position: The position found (only if returns true) +//! \return True if there is a matching entry, False otherwise +static inline bool population_table_position_in_the_master_pop_array( + spike_t spike, uint32_t *position) { + uint32_t imin = 0; + uint32_t imax = master_population_table_length; + + while (imin < imax) { + uint32_t imid = (imax + imin) >> 1; + master_population_table_entry entry = master_population_table[imid]; + if ((spike & entry.mask) == entry.key) { + *position = imid; + return true; + } else if (entry.key < spike) { + + // Entry must be in upper part of the table + imin = imid + 1; + } else { + // Entry must be in lower part of the table + imax = imid; + } + } + return false; +} +//! \} + +//! \name API functions +//! \{ + +bool population_table_initialise( + address_t table_address, address_t synapse_rows_address, + address_t direct_rows_address, uint32_t *row_max_n_words) { + log_debug("Population_table_initialise: starting"); + pop_table_config_t *config = (pop_table_config_t *) table_address; + + master_population_table_length = config->table_length; + log_debug("Master pop table length is %d\n", master_population_table_length); + log_debug("Master pop table entry size is %d\n", + sizeof(master_population_table_entry)); + uint32_t n_master_pop_bytes = + master_population_table_length * sizeof(master_population_table_entry); + log_debug("Pop table size is %d\n", n_master_pop_bytes); + + // only try to malloc if there's stuff to malloc. + if (n_master_pop_bytes != 0) { + master_population_table = spin1_malloc(n_master_pop_bytes); + if (master_population_table == NULL) { + log_error("Could not allocate master population table"); + return false; + } + } + + uint32_t address_list_length = config->addr_list_length; + uint32_t n_address_list_bytes = + address_list_length * sizeof(address_list_entry); + + // only try to malloc if there's stuff to malloc. + if (n_address_list_bytes != 0) { + address_list = spin1_malloc(n_address_list_bytes); + if (address_list == NULL) { + log_error("Could not allocate master population address list"); + return false; + } + } + + log_debug("Pop table size: %u (%u bytes)", + master_population_table_length, n_master_pop_bytes); + log_debug("Address list size: %u (%u bytes)", + address_list_length, n_address_list_bytes); + + // Copy the master population table + spin1_memcpy(master_population_table, config->data, n_master_pop_bytes); + spin1_memcpy(address_list, &config->data[master_population_table_length], + n_address_list_bytes); + + // Store the base address + log_info("The stored synaptic matrix base address is located at: 0x%08x", + synapse_rows_address); + log_info("The direct synaptic matrix base address is located at: 0x%08x", + direct_rows_address); + synaptic_rows_base_address = (uint32_t) synapse_rows_address; + direct_rows_base_address = (uint32_t) direct_rows_address; + + *row_max_n_words = 0xFF + N_SYNAPSE_ROW_HEADER_WORDS; + + print_master_population_table(); + return true; +} + +bool population_table_get_first_address( + spike_t spike, synaptic_row_t *row_address, + size_t *n_bytes_to_transfer) { + // locate the position in the binary search / array + log_debug("Searching for key %d", spike); + + // check we don't have a complete miss + uint32_t position; + if (!population_table_position_in_the_master_pop_array(spike, &position)) { + invalid_master_pop_hits++; + log_debug("Ghost searches: %u\n", ghost_pop_table_searches); + log_debug("Spike %u (= %x): " + "Population not found in master population table", + spike, spike); + return false; + } + log_debug("position = %d", position); + + master_population_table_entry entry = master_population_table[position]; + if (entry.count == 0) { + log_debug("Spike %u (= %x): Population found in master population" + "table but count is 0", spike, spike); + } + + last_spike = spike; + next_item = entry.start; + items_to_go = entry.count; + uint32_t bit_field_id = 0; + if (entry.extra_info_flag) { + extra_info extra = address_list[next_item++].extra; + uint32_t local_neuron_id = get_local_neuron_id(entry, extra, spike); + last_neuron_id = local_neuron_id + get_core_sum(extra, spike); + bit_field_id = local_neuron_id + get_bitfield_sum(extra, spike); + } else { + last_neuron_id = get_neuron_id(entry, spike); + bit_field_id = last_neuron_id; + } + + // check we have a entry in the bit field for this (possible not to due to + // DTCM limitations or router table compression). If not, go to DMA check. + log_debug("Checking bit field"); + if (connectivity_bit_field != NULL && + connectivity_bit_field[position] != NULL) { + log_debug("Can be checked, bitfield is allocated"); + // check that the bit flagged for this neuron id does hit a + // neuron here. If not return false and avoid the DMA check. + if (!bit_field_test( + connectivity_bit_field[position], bit_field_id)) { + log_debug("Tested and was not set"); + bit_field_filtered_packets += 1; + items_to_go = 0; + return false; + } + log_debug("Was set, carrying on"); + } else { + log_debug("Bit field was not set up. " + "either its due to a lack of DTCM, or because the " + "bit field was merged into the routing table"); + } + + log_debug("spike = %08x, entry_index = %u, start = %u, count = %u", + spike, position, next_item, items_to_go); + + // A local address is used here as the interface requires something + // to be passed in but using the address of an argument is odd! + uint32_t local_spike_id; + bool get_next = population_table_get_next_address( + &local_spike_id, row_address, n_bytes_to_transfer); + + // tracks surplus DMAs + if (!get_next) { + log_debug("Found a entry which has a ghost entry for key %d", spike); + ghost_pop_table_searches++; + } + return get_next; +} + +bool population_table_get_next_address( + spike_t *spike, synaptic_row_t *row_address, + size_t *n_bytes_to_transfer) { + // If there are no more items in the list, return false + if (items_to_go == 0) { + return false; + } + + bool is_valid = false; + do { + address_and_row_length item = address_list[next_item].addr; + if (item.address != INVALID_ADDRESS) { + + // If the row is a direct row, indicate this by specifying the + // n_bytes_to_transfer is 0 + if (item.is_single) { + *row_address = (synaptic_row_t) (get_direct_address(item) + + (last_neuron_id * sizeof(uint32_t))); + *n_bytes_to_transfer = 0; + } else { + + uint32_t row_length = get_row_length(item); + uint32_t block_address = get_address(item); + uint32_t stride = (row_length + N_SYNAPSE_ROW_HEADER_WORDS); + uint32_t neuron_offset = last_neuron_id * stride * sizeof(uint32_t); + + *row_address = (synaptic_row_t) (block_address + neuron_offset); + *n_bytes_to_transfer = stride * sizeof(uint32_t); + log_debug("neuron_id = %u, block_address = 0x%.8x, " + "row_length = %u, row_address = 0x%.8x, n_bytes = %u", + last_neuron_id, block_address, row_length, *row_address, + *n_bytes_to_transfer); + *spike = last_spike; + } + is_valid = true; + } + + next_item++; + items_to_go--; + } while (!is_valid && (items_to_go > 0)); + + return is_valid; +} + +//! \} diff --git a/neural_modelling/src/meanfield_fixing/profile_tags.h b/neural_modelling/src/meanfield_fixing/profile_tags.h new file mode 100644 index 00000000000..67eb0d2d723 --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/profile_tags.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Profiler tags +#pragma once + +//! Tags used when profiling sPyNNaker neuron code +enum profiler_tags_e { + PROFILER_TIMER, //!< timer + PROFILER_DMA_READ, //!< DMA read + PROFILER_INCOMING_SPIKE, //!< incoming spike handling + PROFILER_PROCESS_FIXED_SYNAPSES, //!< fixed synapse processing + PROFILER_PROCESS_PLASTIC_SYNAPSES //!< plastic synapse processing +}; diff --git a/neural_modelling/src/meanfield_fixing/regions.h b/neural_modelling/src/meanfield_fixing/regions.h new file mode 100644 index 00000000000..1c02486be9e --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/regions.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Standard layout of DSG regions in neuron code. +//! +//! Note that not all models use all of these regions, but they all use the same +//! region identifier mapping. +#pragma once + +//! DSG region identifiers +typedef enum neuron_regions_e { + SYSTEM_REGION, //!< simulation system; 0 + NEURON_PARAMS_REGION, //!< neuron parameters; 1 + SYNAPSE_PARAMS_REGION, //!< synapse parameters; 2 + POPULATION_TABLE_REGION, //!< master population table; 3 + SYNAPTIC_MATRIX_REGION, //!< synaptic matrix; 4 + SYNAPSE_DYNAMICS_REGION, //!< synapse dynamics; 5 + STRUCTURAL_DYNAMICS_REGION, //!< structural dynamics; 6 + NEURON_RECORDING_REGION, //!< recording; 7 + PROVENANCE_DATA_REGION, //!< provenance; 8 + PROFILER_REGION, //!< profiling; 9 + CONNECTOR_BUILDER_REGION, //!< connection building; 10 + DIRECT_MATRIX_REGION, //!< direct synaptic matrix; 11 + BIT_FIELD_FILTER_REGION, //!< bitfield filter; 12 + BIT_FIELD_BUILDER, //!< bitfield builder parameters; 13 + BIT_FIELD_KEY_MAP //!< bitfield key map; 14 +} regions_e; diff --git a/neural_modelling/src/meanfield_fixing/spike_processing.c b/neural_modelling/src/meanfield_fixing/spike_processing.c new file mode 100644 index 00000000000..80b6654e378 --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/spike_processing.c @@ -0,0 +1,521 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Implementation of non-inlined API in spike_processing.h +#include "spike_processing.h" +#include "population_table/population_table.h" +#include "synapse_row.h" +#include "synapses.h" +#include "direct_synapses.h" +#include "structural_plasticity/synaptogenesis_dynamics.h" +#include +#include +#include +#include + +//! DMA buffer structure combines the row read from SDRAM with information +//! about the read. +typedef struct dma_buffer { + //! Address in SDRAM to write back plastic region to + synaptic_row_t sdram_writeback_address; + + //! \brief Key of originating spike + //! \details used to allow row data to be re-used for multiple spikes + spike_t originating_spike; + + //! Number of bytes transferred in the read + uint32_t n_bytes_transferred; + + //! Row data + synaptic_row_t row; +} dma_buffer; + +//! The number of DMA Buffers to use +#define N_DMA_BUFFERS 2 + +//! DMA tags +enum spike_processing_dma_tags { + //! Tag of a DMA read of a full synaptic row + DMA_TAG_READ_SYNAPTIC_ROW, + //! Tag of a DMA write of the plastic region of a synaptic row + DMA_TAG_WRITE_PLASTIC_REGION +}; + +//! The current timer tick value +extern uint32_t time; + +//! True if the DMA "loop" is currently running +static volatile bool dma_busy; + +//! The DTCM buffers for the synapse rows +static dma_buffer dma_buffers[N_DMA_BUFFERS]; + +//! The index of the next buffer to be filled by a DMA +static uint32_t next_buffer_to_fill; + +//! The index of the buffer currently being filled by a DMA read +static uint32_t buffer_being_read; + +//! Number of outstanding synaptogenic rewirings +static volatile uint32_t rewires_to_do = 0; + +//! \brief The number of rewires to do when the DMA completes. +//! \details When a DMA is first set up, only this or ::dma_n_spikes can be 1 +//! with the other being 0. +static uint32_t dma_n_rewires; + +//! \brief The number of spikes to do when the DMA completes. +//! \details When a DMA is first set up, only this or ::dma_n_rewires can be 1 +//! with the other being 0. +static uint32_t dma_n_spikes; + +//! the number of DMA completes (used in provenance generation) +static uint32_t dma_complete_count; + +//! the number of spikes that were processed (used in provenance generation) +static uint32_t spike_processing_count; + +//! The number of successful rewires +static uint32_t n_successful_rewires; + +//! \brief How many packets were lost from the input buffer because of +//! late arrival +static uint32_t count_input_buffer_packets_late; + +//! tracker of how full the input buffer got. +static uint32_t biggest_fill_size_of_input_buffer; + +//! \brief Whether if we should clear packets from the input buffer at the +//! end of a timer tick. +static bool clear_input_buffers_of_late_packets; + +//! the number of packets received this time step +static struct { + uint32_t time; + uint32_t packets_this_time_step; +} p_per_ts_struct; + +//! the region to record the packets per timestep in +static uint32_t p_per_ts_region; + +/* PRIVATE FUNCTIONS - static for inlining */ + +//! \brief Perform a DMA read of a synaptic row +//! \param[in] row: Where in SDRAM to read the row from +//! \param[in] n_bytes_to_transfer: The size of the synaptic row +//! \param[in] spike: The spike that triggered this read +static inline void do_dma_read( + synaptic_row_t row, size_t n_bytes_to_transfer, spike_t spike) { + // Write the SDRAM address of the plastic region and the + // Key of the originating spike to the beginning of DMA buffer + dma_buffer *next_buffer = &dma_buffers[next_buffer_to_fill]; + next_buffer->sdram_writeback_address = row; + next_buffer->originating_spike = spike; + next_buffer->n_bytes_transferred = n_bytes_to_transfer; + + // Start a DMA transfer to fetch this synaptic row into current + // buffer + buffer_being_read = next_buffer_to_fill; + while (!spin1_dma_transfer( + DMA_TAG_READ_SYNAPTIC_ROW, row, next_buffer->row, DMA_READ, + n_bytes_to_transfer)) { + // Do Nothing + } + next_buffer_to_fill = (next_buffer_to_fill + 1) % N_DMA_BUFFERS; +} + +//! \brief Check if there is anything to do. If not, DMA is not busy +//! \param[out] row: +//! The address of the synaptic row that has been processed +//! \param[out] n_bytes_to_transfer: The size of the processed synaptic row +//! \param[out] spike: The spike being processed +//! \param[in,out] n_rewire: Accumulator of number of rewirings +//! \param[in,out] n_process_spike: Accumulator of number of processed spikes +//! \return True if there's something to do +static inline bool is_something_to_do( + synaptic_row_t *row, size_t *n_bytes_to_transfer, + spike_t *spike, uint32_t *n_rewire, uint32_t *n_process_spike) { + // Disable interrupts here as dma_busy modification is a critical section + uint cpsr = spin1_int_disable(); + + // Check for synaptic rewiring + while (rewires_to_do) { + rewires_to_do--; + spin1_mode_restore(cpsr); + if (synaptogenesis_dynamics_rewire(time, spike, row, + n_bytes_to_transfer)) { + *n_rewire += 1; + return true; + } + cpsr = spin1_int_disable(); + } + + // Is there another address in the population table? + spin1_mode_restore(cpsr); + if (population_table_get_next_address(spike, row, n_bytes_to_transfer)) { + *n_process_spike += 1; + return true; + } + cpsr = spin1_int_disable(); + + // track for provenance + uint32_t input_buffer_filled_size = in_spikes_size(); + if (biggest_fill_size_of_input_buffer < input_buffer_filled_size) { + biggest_fill_size_of_input_buffer = input_buffer_filled_size; + } + + // Are there any more spikes to process? + while (in_spikes_get_next_spike(spike)) { + // Enable interrupts while looking up in the master pop table, + // as this can be slow + spin1_mode_restore(cpsr); + if (population_table_get_first_address( + *spike, row, n_bytes_to_transfer)) { + synaptogenesis_spike_received(time, *spike); + *n_process_spike += 1; + return true; + } + + // Disable interrupts before checking if there is another spike + cpsr = spin1_int_disable(); + } + + // If nothing to do, the DMA is not busy + dma_busy = false; + + // Restore interrupts + spin1_mode_restore(cpsr); + return false; +} + +//! \brief Set up a new synaptic DMA read. +//! \details +//! If a current_buffer is passed in, any spike found that matches the +//! originating spike of the buffer will increment a count, and the DMA of that +//! row will be skipped. The number of times a row should be rewired and the +//! number of times synaptic processing should be done on a row is returned. +//! +//! Calls is_something_to_do(), do_direct_row() and do_dma_read() +//! \param[in] current_buffer: The current buffer, if any. +//! \param[in,out] n_rewires: Accumulator of number of rewirings +//! \param[in,out] n_synapse_processes: +//! Accumulator of number of synapses processed +static void setup_synaptic_dma_read(dma_buffer *current_buffer, + uint32_t *n_rewires, uint32_t *n_synapse_processes) { + // Set up to store the DMA location and size to read + synaptic_row_t row; + size_t n_bytes_to_transfer; + spike_t spike; + dma_n_spikes = 0; + dma_n_rewires = 0; + + // Keep looking if there is something to do until a DMA can be done + bool setup_done = false; + while (!setup_done && is_something_to_do(&row, &n_bytes_to_transfer, + &spike, &dma_n_rewires, &dma_n_spikes)) { + if (current_buffer != NULL && + current_buffer->sdram_writeback_address == row) { + // If we can reuse the row, add on what we can use it for + // Note that only one of these will have a value of 1 with the + // other being set to 0, but we add both as it is simple + *n_rewires += dma_n_rewires; + *n_synapse_processes += dma_n_spikes; + dma_n_rewires = 0; + dma_n_spikes = 0; + } else if (n_bytes_to_transfer == 0) { + // If the row is in DTCM, process the row now + synaptic_row_t single_fixed_synapse = + direct_synapses_get_direct_synapse(row); + bool write_back; + synapses_process_synaptic_row( + time, single_fixed_synapse, &write_back); + dma_n_rewires = 0; + dma_n_spikes = 0; + } else { + // If the row is in SDRAM, set up the transfer and we are done + do_dma_read(row, n_bytes_to_transfer, spike); + setup_done = true; + } + + // needs to be here to ensure that its only recording actual spike + // processing and not the surplus DMA requests. + spike_processing_count++; + } +} + +//! \brief Set up a DMA write of synaptic data. +//! \param[in] dma_buffer_index: Index of DMA buffer to use +//! \param[in] plastic_only: If false, write the whole synaptic row. +//! If true, only write the plastic data region of the synaptic row. +static inline void setup_synaptic_dma_write( + uint32_t dma_buffer_index, bool plastic_only) { + // Get pointer to current buffer + dma_buffer *buffer = &dma_buffers[dma_buffer_index]; + + // Get the number of plastic bytes and the write back address from the + // synaptic row + size_t write_size = buffer->n_bytes_transferred; + void *sdram_start_address = buffer->sdram_writeback_address; + void *dtcm_start_address = buffer->row; + if (plastic_only) { + write_size = synapse_row_plastic_size(buffer->row) * sizeof(uint32_t); + sdram_start_address = synapse_row_plastic_region( + buffer->sdram_writeback_address); + dtcm_start_address = synapse_row_plastic_region(buffer->row); + } + + log_debug("Writing back %u bytes of plastic region to %08x for spike %u", + write_size, sdram_start_address, buffer->originating_spike); + + // Start transfer + while (!spin1_dma_transfer(DMA_TAG_WRITE_PLASTIC_REGION, sdram_start_address, + dtcm_start_address, DMA_WRITE, write_size)) { + // Do Nothing + } +} + +//! \brief Called when a multicast packet is received +//! \param[in] key: The key of the packet. The spike. +//! \param payload: the payload of the packet. The count. +static void multicast_packet_received_callback(uint key, uint payload) { + p_per_ts_struct.packets_this_time_step += 1; + + // handle the 2 cases separately + if (payload == 0) { + log_debug( + "Received spike %x at %d, DMA Busy = %d", key, time, dma_busy); + // set to 1 to work with the loop. + payload = 1; + } else { + log_debug( + "Received spike %x with payload %d at %d, DMA Busy = %d", + key, payload, time, dma_busy); + } + + // cycle through the packet insertion + for (uint count = payload; count > 0; count--) { + in_spikes_add_spike(key); + } + + // If we're not already processing synaptic DMAs, + // flag pipeline as busy and trigger a feed event + // NOTE: locking is not used here because this is assumed to be FIQ + if (!dma_busy) { + log_debug("Sending user event for new spike"); + if (spin1_trigger_user_event(0, 0)) { + dma_busy = true; + } else { + log_warning("Could not trigger user event\n"); + } + } +} + +//! \brief Called when a DMA completes +//! \param unused: unused +//! \param[in] tag: What sort of DMA has finished? +static void dma_complete_callback(UNUSED uint unused, uint tag) { + + // increment the dma complete count for provenance generation + dma_complete_count++; + + log_debug("DMA transfer complete at time %u with tag %u", time, tag); + + // Get pointer to current buffer + uint32_t current_buffer_index = buffer_being_read; + dma_buffer *current_buffer = &dma_buffers[current_buffer_index]; + + // Start the next DMA transfer and get a count of the rewires and spikes + // that can be done on this row now (there might be more while the DMA + // was in progress). Note that either dma_n_rewires or dma_n_spikes is set + // to 1 here, with the other being 0. We take a copy of the count and this + // is the value added to for this processing, as setup_synaptic_dma will + // count repeats of the current spike + uint32_t n_rewires = dma_n_rewires; + uint32_t n_spikes = dma_n_spikes; + setup_synaptic_dma_read(current_buffer, &n_rewires, &n_spikes); + + // Assume no write back but assume any write back is plastic only + bool write_back = false; + bool plastic_only = true; + + // If rewiring, do rewiring first + for (uint32_t i = 0; i < n_rewires; i++) { + if (synaptogenesis_row_restructure(time, current_buffer->row)) { + write_back = true; + plastic_only = false; + n_successful_rewires++; + } + } + + // Process synaptic row repeatedly for any upcoming spikes + while (n_spikes > 0) { + + // Process synaptic row, writing it back if it's the last time + // it's going to be processed + bool write_back_now = false; + if (!synapses_process_synaptic_row( + time, current_buffer->row, &write_back_now)) { + log_error( + "Error processing spike 0x%.8x for address 0x%.8x" + " (local=0x%.8x)", + current_buffer->originating_spike, + current_buffer->sdram_writeback_address, + current_buffer->row); + + // Print out the row for debugging + address_t row = (address_t) current_buffer->row; + for (uint32_t i = 0; + i < (current_buffer->n_bytes_transferred >> 2); i++) { + log_error("%u: 0x%.8x", i, row[i]); + } + rt_error(RTE_SWERR); + } + + write_back |= write_back_now; + n_spikes--; + } + + if (write_back) { + setup_synaptic_dma_write(current_buffer_index, plastic_only); + } +} + +//! \brief Called when a user event is received +//! \param unused0: unused +//! \param unused1: unused +void user_event_callback(UNUSED uint unused0, UNUSED uint unused1) { + // Reset the counters as this is a new process + dma_n_rewires = 0; + dma_n_spikes = 0; + + if (buffer_being_read < N_DMA_BUFFERS) { + // If the DMA buffer is full of valid data, attempt to reuse it on the + // next data to be used, as this might be able to make use of the buffer + // without transferring data + dma_complete_callback(0, DMA_TAG_READ_SYNAPTIC_ROW); + } else { + // If the DMA buffer is invalid, just do the first transfer possible + setup_synaptic_dma_read(NULL, NULL, NULL); + } +} + +/* INTERFACE FUNCTIONS - cannot be static */ +//! \brief clears the input buffer of packets and records them +void spike_processing_clear_input_buffer(timer_t time) { + uint32_t n_spikes = in_spikes_size(); + if (clear_input_buffers_of_late_packets) { + spin1_dma_flush(); + in_spikes_clear(); + dma_busy = false; + } + + // Record the number of packets received last timer tick + p_per_ts_struct.time = time; + recording_record(p_per_ts_region, &p_per_ts_struct, sizeof(p_per_ts_struct)); + p_per_ts_struct.packets_this_time_step = 0; + + // Record the count whether clearing or not for provenance + count_input_buffer_packets_late += n_spikes; + +} + +bool spike_processing_initialise( // EXPORTED + size_t row_max_n_words, uint mc_packet_callback_priority, + uint user_event_priority, uint incoming_spike_buffer_size, + bool clear_input_buffers_of_late_packets_init, + uint32_t packets_per_timestep_region) { + // Allocate the DMA buffers + for (uint32_t i = 0; i < N_DMA_BUFFERS; i++) { + dma_buffers[i].row = spin1_malloc(row_max_n_words * sizeof(uint32_t)); + if (dma_buffers[i].row == NULL) { + log_error("Could not initialise DMA buffers"); + return false; + } + log_debug("DMA buffer %u allocated at 0x%08x", + i, dma_buffers[i].row); + } + dma_busy = false; + clear_input_buffers_of_late_packets = + clear_input_buffers_of_late_packets_init; + next_buffer_to_fill = 0; + buffer_being_read = N_DMA_BUFFERS; + p_per_ts_region = packets_per_timestep_region; + + // Allocate incoming spike buffer + if (!in_spikes_initialize_spike_buffer(incoming_spike_buffer_size)) { + return false; + } + + // Set up the callbacks + spin1_callback_on(MC_PACKET_RECEIVED, + multicast_packet_received_callback, mc_packet_callback_priority); + spin1_callback_on(MCPL_PACKET_RECEIVED, + multicast_packet_received_callback, mc_packet_callback_priority); + simulation_dma_transfer_done_callback_on( + DMA_TAG_READ_SYNAPTIC_ROW, dma_complete_callback); + spin1_callback_on(USER_EVENT, user_event_callback, user_event_priority); + + return true; +} + +uint32_t spike_processing_get_buffer_overflows(void) { // EXPORTED + // Check for buffer overflow + return in_spikes_get_n_buffer_overflows(); +} + +uint32_t spike_processing_get_dma_complete_count(void) { + return dma_complete_count; +} + +uint32_t spike_processing_get_spike_processing_count(void) { + return spike_processing_count; +} + +uint32_t spike_processing_get_successful_rewires(void) { // EXPORTED + return n_successful_rewires; +} + +uint32_t spike_processing_get_n_packets_dropped_from_lateness(void) { // EXPORTED + return count_input_buffer_packets_late; +} + +uint32_t spike_processing_get_max_filled_input_buffer_size(void) { // EXPORTED + return biggest_fill_size_of_input_buffer; +} + +//! \brief set the number of times spike_processing has to attempt rewiring +//! \return currently, always true +bool spike_processing_do_rewiring(int number_of_rewires) { + // disable interrupts + uint cpsr = spin1_int_disable(); + rewires_to_do += number_of_rewires; + + // If we're not already processing synaptic DMAs, + // flag pipeline as busy and trigger a feed event + if (!dma_busy) { + log_debug("Sending user event for rewiring"); + if (spin1_trigger_user_event(0, 0)) { + dma_busy = true; + } else { + log_debug("Could not trigger user event\n"); + } + } + // enable interrupts + spin1_mode_restore(cpsr); + return true; +} diff --git a/neural_modelling/src/meanfield_fixing/spike_processing.h b/neural_modelling/src/meanfield_fixing/spike_processing.h new file mode 100644 index 00000000000..0958e78b874 --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/spike_processing.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Spike processing API +#ifndef _SPIKE_PROCESSING_H_ +#define _SPIKE_PROCESSING_H_ + +#include +#include +#include + +//! \brief Initialise the spike processing system +//! \param[in] row_max_n_bytes: The maximum size of a synaptic row +//! \param[in] mc_packet_callback_priority: +//! Multicast packet receive interrupt priority +//! \param[in] user_event_priority: User event interrupt priority +//! \param[in] incoming_spike_buffer_size: Size of buffer for receiving spikes +//! \param[in] packets_per_timestep_region: +//! The recording region to use for the packets per timestep +//! \return True if initialisation succeeded +bool spike_processing_initialise( + size_t row_max_n_bytes, uint mc_packet_callback_priority, + uint user_event_priority, uint incoming_spike_buffer_size, + bool clear_input_buffers_of_late_packets_init, + uint32_t packets_per_timestep_region); + +//! \brief Gets the number of times the input buffer has overflowed +//! \return the number of times the input buffer has overflowed +uint32_t spike_processing_get_buffer_overflows(void); + +//! \brief Gets the number of DMA's that were completed +//! \return the number of DMA's that were completed. +uint32_t spike_processing_get_dma_complete_count(void); + +//! \brief Gets the number of spikes that were processed +//! \return the number of spikes that were processed +uint32_t spike_processing_get_spike_processing_count(void); + +//! \brief Gets the number of successful rewires performed +//! \return the number of successful rewires +uint32_t spike_processing_get_successful_rewires(void); + +//! \brief Set the number of times spike_processing has to attempt rewiring. +//! \param[in] number_of_rewires: The number of rewirings to perform +//! \return currently always true +bool spike_processing_do_rewiring(int number_of_rewires); + +//! \brief return the number of packets dropped by the input buffer as they +//! arrived too late to be processed +//! \return the number of packets dropped. +uint32_t spike_processing_get_n_packets_dropped_from_lateness(void); + +//! \brief clears the input buffer of packets +//! \param[in] time: The current timestep +void spike_processing_clear_input_buffer(timer_t time); + +//! \brief returns how many packets were at max inside the input buffer at +//! any given point. +//! \return the max size the input buffer reached +uint32_t spike_processing_get_max_filled_input_buffer_size(void); + +#endif // _SPIKE_PROCESSING_H_ diff --git a/neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis/elimination/elimination.h b/neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis/elimination/elimination.h new file mode 100644 index 00000000000..4e4bb21b98f --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis/elimination/elimination.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \dir +//! \brief Synapse elimination algorithms +//! \file +//! \brief API for synapse elimination +#ifndef _ELIMINATION_H_ +#define _ELIMINATION_H_ + +#include +typedef struct elimination_params elimination_params_t; + +//! \brief Read and return an elimination parameter data structure from the +//! data stream +//! \param[in,out] data: The data stream to read from, updated to the new +//! position after the read is done +//! \return the read parameters data structure +elimination_params_t *synaptogenesis_elimination_init(uint8_t **data); + +//! \brief Elimination rule for synaptogenesis +//! \param[in,out] current_state: Pointer to current state +//! \param[in] params: The elimination rule configuration. +//! \param[in] time: Time of elimination +//! \param[in,out] row: The row to eliminate from +//! \return if row was modified +static inline bool synaptogenesis_elimination_rule( + current_state_t *current_state, const elimination_params_t *params, + uint32_t time, synaptic_row_t row); + +#endif // _ELIMINATION_H_ diff --git a/neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis/elimination/elimination_random_by_weight_impl.c b/neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis/elimination/elimination_random_by_weight_impl.c new file mode 100644 index 00000000000..abd3d0efb51 --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis/elimination/elimination_random_by_weight_impl.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Support code for elimination_random_by_weight_impl.h +#include "elimination_random_by_weight_impl.h" + +elimination_params_t *synaptogenesis_elimination_init(uint8_t **data) { + elimination_params_t *elim_params = + spin1_malloc(sizeof(elimination_params_t)); + if (elim_params == NULL) { + log_error("Out of memory when allocating parameters"); + rt_error(RTE_SWERR); + } + spin1_memcpy(elim_params, *data, sizeof(elimination_params_t)); + log_debug("Elimination random by weight prob_dep=%u prob_pot=%u thresh=%u", + elim_params->prob_elim_depression, + elim_params->prob_elim_potentiation, + elim_params->threshold); + *data += sizeof(elimination_params_t); + return elim_params; +} diff --git a/neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis/elimination/elimination_random_by_weight_impl.h b/neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis/elimination/elimination_random_by_weight_impl.h new file mode 100644 index 00000000000..3a6bb3d4bc2 --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis/elimination/elimination_random_by_weight_impl.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Synapse elimination by weighted random selection +#ifndef _ELIMINATION_RANDOM_BY_WEIGHT_IMPL_H_ +#define _ELIMINATION_RANDOM_BY_WEIGHT_IMPL_H_ + +#include "elimination.h" + +//! Configuration of synapse elimination rule +struct elimination_params { + //! Probability of elimination of depressed synapse + uint32_t prob_elim_depression; + //! Probability of elimination of potentiated synapse + uint32_t prob_elim_potentiation; + //! Threshold below which a synapse is depressed, and above which it is + //! potentiated + uint32_t threshold; +}; + +//! \brief Elimination rule for synaptogenesis +//! \param[in,out] current_state: Pointer to current state +//! \param[in] params: The elimination rule configuration. +//! \param[in] time: Time of elimination +//! \param[in,out] row: The row to eliminate from +//! \return if row was modified +static inline bool synaptogenesis_elimination_rule( + current_state_t *restrict current_state, + const elimination_params_t *params, + UNUSED uint32_t time, synaptic_row_t restrict row) { + uint32_t random_number = mars_kiss64_seed(*(current_state->local_seed)); + + // Is weight depressed? + if (current_state->weight < params->threshold && + random_number > params->prob_elim_depression) { + return false; + } + + // Is weight potentiated or unchanged? + if (current_state->weight >= params->threshold && + random_number > params->prob_elim_potentiation) { + return false; + } + + return sp_structs_remove_synapse(current_state, row); +} + +#endif // _ELIMINATION_RANDOM_BY_WEIGHT_IMPL_H_ diff --git a/neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis/formation/formation.h b/neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis/formation/formation.h new file mode 100644 index 00000000000..a8f25371e9f --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis/formation/formation.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \dir +//! \brief Synapse formation algorithms +//! \file +//! \brief API for synapse formation +#ifndef _FORMATION_H_ +#define _FORMATION_H_ + +#include +typedef struct formation_params formation_params_t; + +//! \brief Read and return an formation parameter data structure from the +//! data stream +//! \param[in,out] data: The data stream to read from, updated to the new +//! position after the read is done +//! \return the read parameters data structure +formation_params_t *synaptogenesis_formation_init(uint8_t **data); + +//! \brief Formation rule for synaptogenesis; picks what neuron in the +//! _current_ population will have a synapse added, and then performs the +//! addition. +//! \param[in] current_state: Pointer to current state +//! \param[in] params: Pointer to rewiring data +//! \param[in] time: Time of formation +//! \param[in] row: The row to form within +//! \return if row was modified +static inline bool synaptogenesis_formation_rule( + current_state_t *current_state, const formation_params_t *params, + uint32_t time, synaptic_row_t row); + +#endif // _FORMATION_H_ diff --git a/neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis/formation/formation_distance_dependent_impl.c b/neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis/formation/formation_distance_dependent_impl.c new file mode 100644 index 00000000000..61da6ea9a35 --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis/formation/formation_distance_dependent_impl.c @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Support code for formation_distance_dependent_impl.h +#include "formation_distance_dependent_impl.h" + +formation_params_t *synaptogenesis_formation_init(uint8_t **data) { + // Reference the parameters to read the sizes + formation_params_t *form_params = (formation_params_t *) *data; + uint32_t data_size = sizeof(formation_params_t) + (sizeof(uint16_t) * + (form_params->ff_prob_size + form_params->lat_prob_size)); + + // Allocate the space for the data and copy it in + form_params = spin1_malloc(data_size); + if (form_params == NULL) { + log_error("Out of memory when allocating parameters"); + rt_error(RTE_SWERR); + } + spin1_memcpy(form_params, *data, data_size); + log_debug("Formation distance dependent %u bytes, grid=(%u, %u), %u ff probs, %u lat probs", + data_size, form_params->grid_x, form_params->grid_y, + form_params->ff_prob_size, form_params->lat_prob_size); + *data += data_size; + + return form_params; +} diff --git a/neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis/formation/formation_distance_dependent_impl.h b/neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis/formation/formation_distance_dependent_impl.h new file mode 100644 index 00000000000..acc5ff9eca1 --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis/formation/formation_distance_dependent_impl.h @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Synapse formation using a distance-dependent rule +#ifndef _FORMATION_DISTANCE_DEPENDENT_H_ +#define _FORMATION_DISTANCE_DEPENDENT_H_ + +#include "formation.h" + +//! Largest value in a `uint16_t` +#define MAX_SHORT 65535 + +//! \brief Configuration of synapse formation rule +//! +//! Describes the size of grid containing the neurons (the total number of +//! neurons probably ought to be equal to or just a bit under \a grid_x × +//! \a grid_y), and two tables of distance-dependent connection probabilities. +//! The FF table describes ??? connection probabilities, and the LAT table +//! describes lateral connection probabilities. Both are keyed by the _square_ +//! of the inter-neuron distance. +//! +//! Note that both pre- and post-neurons are assumed to be on the same size of +//! grid, and the inter-layer distance is assumed to be constant (so it can be +//! accounted for in the construction of the tables). +struct formation_params { + //! Size of grid containing neurons, X-dimension + uint32_t grid_x; + //! Size of grid containing neurons, Y-dimension + uint32_t grid_y; + //! Reciprocal of grid_x + unsigned long fract grid_x_recip; + //! Reciprocal of grid_y + unsigned long fract grid_y_recip; + //! Size of FF probability table + uint32_t ff_prob_size; + //! Size of LAT probability table + uint32_t lat_prob_size; + //! Concatenated probability tables; first the FF table, then the LAT table + uint16_t prob_tables[]; +}; + +//! \brief abs function +//! \param[in] a: value (must not be `INT_MIN`) +//! \return Absolute value of \a a +static int my_abs(int a) { + return a < 0 ? -a : a; +} + +//! \brief Formation rule for synaptogenesis; picks what neuron in the +//! _current_ population will have a synapse added, and then performs the +//! addition. +//! \param[in] current_state: Pointer to current state +//! \param[in] params: Pointer to rewiring data +//! \param[in] time: Time of formation +//! \param[in] row: The row to form within +//! \return if row was modified +static inline bool synaptogenesis_formation_rule( + current_state_t *current_state, const formation_params_t *params, + UNUSED uint32_t time, synaptic_row_t row) { + // Compute distances + // To do this I need to take the DIV and MOD of the + // post-synaptic neuron ID, of the pre-synaptic neuron ID + // Compute the distance of these 2 measures + uint32_t pre_x, pre_y, post_x, post_y; + // Pre computation requires querying the table with global information + uint32_t pre_global_id = current_state->key_atom_info->lo_atom + + current_state->pre_syn_id; + uint32_t post_global_id = current_state->post_syn_id + + current_state->post_low_atom; + + if (params->grid_x > 1) { + pre_x = muliulr(pre_global_id, params->grid_x_recip); + post_x = muliulr(post_global_id, params->grid_x_recip); + } else { + pre_x = 0; + post_x = 0; + } + + if (params->grid_y > 1) { + uint32_t pre_y_div = muliulr(pre_global_id, params->grid_y_recip); + uint32_t post_y_div = muliulr(post_global_id, params->grid_y_recip); + pre_y = pre_global_id - (pre_y_div * params->grid_y); + post_y = post_global_id - (post_y_div * params->grid_y); + } else { + pre_y = 0; + post_y = 0; + } + + // With periodic boundary conditions + uint32_t delta_x, delta_y; + delta_x = my_abs(pre_x - post_x); + delta_y = my_abs(pre_y - post_y); + + if (delta_x > params->grid_x >> 1 && params->grid_x > 1) { + delta_x -= params->grid_x; + } + + if (delta_y > params->grid_y >> 1 && params->grid_y > 1) { + delta_y -= params->grid_y; + } + + uint32_t distance = delta_x * delta_x + delta_y * delta_y; + + // Distance based probability extracted from the appropriate LUT + uint16_t probability; + int16_t controls = current_state->pre_population_info->sp_control; + if (!(controls & IS_CONNECTION_LAT)) { + if (distance >= params->ff_prob_size) { + return false; + } + probability = params->prob_tables[distance]; + } else { + if (distance >= params->lat_prob_size) { + return false; + } + probability = params->prob_tables[params->ff_prob_size + distance]; + } + uint32_t r = rand_int(MAX_SHORT, *(current_state->local_seed)); + if (r > probability) { + return false; + } + + return sp_structs_add_synapse(current_state, row); +} + +#endif // _FORMATION_DISTANCE_DEPENDENT_H_ diff --git a/neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis/partner_selection/last_neuron_selection_impl.c b/neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis/partner_selection/last_neuron_selection_impl.c new file mode 100644 index 00000000000..fbd102f1a0d --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis/partner_selection/last_neuron_selection_impl.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Support code for last_neuron_selection_impl.h +#include "last_neuron_selection_impl.h" + +spike_t* last_spikes_buffer[2]; +uint32_t n_spikes[2]; +//! Size of each sub-array within ::last_spikes_buffer +uint32_t last_spikes_buffer_size; +//! The time of the most recently-considered spike +uint32_t last_time; + +void partner_init(uint8_t **data) { + last_spikes_buffer_size = ((uint32_t *) *data)[0]; + log_debug("Last neuron selection, buffer size = %u", last_spikes_buffer_size); + for (uint32_t i = 0; i < 2; i++) { + last_spikes_buffer[i] = + spin1_malloc(last_spikes_buffer_size * sizeof(spike_t)); + if (last_spikes_buffer[i] == NULL) { + log_error("Out of memory when creating last spikes buffer"); + rt_error(RTE_SWERR); + } + n_spikes[i] = 0; + } + *data += sizeof(uint32_t); +} diff --git a/neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis/partner_selection/last_neuron_selection_impl.h b/neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis/partner_selection/last_neuron_selection_impl.h new file mode 100644 index 00000000000..c10870437e9 --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis/partner_selection/last_neuron_selection_impl.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Recently spiked partners selection rule +#ifndef _LAST_NEURON_SELECTION_IMPL_H_ +#define _LAST_NEURON_SELECTION_IMPL_H_ + +#include "partner.h" +#include + +// Include debug header for log_info etc +#include + +//! \brief Spike accumulation buffers +//! \details Two arrays, one for current timestep, one for previous +extern spike_t* last_spikes_buffer[2]; +//! \brief Spike buffer counters +//! \details Two counters, one for current timestep, one for previous +extern uint32_t n_spikes[2]; + +//! \brief Notifies the rule that a spike has been received +//! \param[in] time: The time that the spike was received at +//! \param[in] spike: +//! The spike that was received (includes the sending neuron ID) +static inline void partner_spike_received(uint32_t time, spike_t spike) { + extern uint32_t last_spikes_buffer_size; + extern uint32_t last_time; + + uint32_t buffer = time & 0x1; + if (time != last_time) { + last_time = time; + n_spikes[buffer] = 0; + } + if (n_spikes[buffer] < last_spikes_buffer_size) { + last_spikes_buffer[buffer][n_spikes[buffer]++] = spike; + } +} + +//! \brief Choose the potential (remote) synaptic partner +//! \details Randomly (with uniform probability) select one of the last received +//! spikes, and uses the source neuron from that. +//! \param[in] time: The current time +//! \param[out] population_id: The ID of the other population +//! \param[out] sub_population_id: The ID of the subpopulation (corresponds to +//! remote SpiNNaker core handling the population) +//! \param[out] neuron_id: The ID of the neuron within the subpopulation +//! \param[out] spike: The spike that made this a meaningful choice +//! \param[out] m_pop_index: The master population table index +//! \return True if a choice was made +static inline bool potential_presynaptic_partner( + uint32_t time, uint32_t *restrict population_id, + uint32_t *restrict sub_population_id, uint32_t *restrict neuron_id, + spike_t *restrict spike, uint32_t *restrict m_pop_index) { + extern rewiring_data_t rewiring_data; + extern pre_pop_info_table_t pre_info; + + uint32_t buffer = (time - 1) & 0x1; + if (!n_spikes[buffer]) { + return false; + } + uint32_t offset = rand_int(n_spikes[buffer], rewiring_data.local_seed); + *spike = last_spikes_buffer[buffer][offset]; + return sp_structs_find_by_spike(&pre_info, *spike, neuron_id, + population_id, sub_population_id, m_pop_index); +} + +#endif // _LAST_NEURON_SELECTION_IMPL_H_ diff --git a/neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis/partner_selection/partner.h b/neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis/partner_selection/partner.h new file mode 100644 index 00000000000..c4d5b71cc3b --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis/partner_selection/partner.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \dir +//! \brief Partner selection rule +//! \file +//! \brief Partner selection rule common API +#ifndef _PARTNER_SELECTION_H_ +#define _PARTNER_SELECTION_H_ + +#include + +// MARS KISS 64 (RNG) +#include +// Bit manipulation after RNG +#include + +#include + +//! value to be returned when there is no valid partner selection +#define INVALID_SELECTION ((spike_t) - 1) + +//! \brief Initialise the partner selection rule +//! \param[in,out] data: A variable holding the location in SDRAM to configure +//! the rule from. Will be updated to point to the first location after the +//! configuration data. +void partner_init(uint8_t **data); + +//! \brief Notifies the rule that a spike has been received +//! \param[in] time: The time that the spike was received at +//! \param[in] spike: +//! The spike that was received (includes the sending neuron ID) +static inline void partner_spike_received(uint32_t time, spike_t spike); + +//! \brief Choose the potential (remote) synaptic partner +//! \param[in] time: The current time +//! \param[out] population_id: The ID of the other population +//! \param[out] sub_population_id: The ID of the subpopulation (corresponds to +//! remote SpiNNaker core handling the population) +//! \param[out] neuron_id: The ID of the neuron within the subpopulation +//! \param[out] spike: The spike that made this a meaningful choice +//! \param[out] m_pop_index: The master population table index +//! \return True if a choice was made +static inline bool potential_presynaptic_partner( + uint32_t time, uint32_t *restrict population_id, + uint32_t *restrict sub_population_id, + uint32_t *restrict neuron_id, spike_t *restrict spike, + uint32_t *restrict m_pop_index); + +#endif // _PARTNER_H_ diff --git a/neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis/partner_selection/random_selection_impl.c b/neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis/partner_selection/random_selection_impl.c new file mode 100644 index 00000000000..0ce723acdd9 --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis/partner_selection/random_selection_impl.c @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Support code for random_selection_impl.h +#include "random_selection_impl.h" + +void partner_init(UNUSED uint8_t **data) { +} diff --git a/neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis/partner_selection/random_selection_impl.h b/neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis/partner_selection/random_selection_impl.h new file mode 100644 index 00000000000..a7b252d4efc --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis/partner_selection/random_selection_impl.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Random partner selection rule +#ifndef _RANDOM_SELECTION_IMPL_H_ +#define _RANDOM_SELECTION_IMPL_H_ + +#include "partner.h" +#include +#include + +//! \brief Notifies the rule that a spike has been received +//! \details Not used by this rule +//! \param[in] time: The time that the spike was received at +//! \param[in] spike: +//! The spike that was received (includes the sending neuron ID) +static inline void partner_spike_received( + UNUSED uint32_t time, UNUSED spike_t spike) { +} + +//! \brief Choose the potential (remote) synaptic partner +//! \param[in] time: The current time +//! \param[out] population_id: The ID of the other population +//! \param[out] sub_population_id: The ID of the subpopulation (corresponds to +//! remote SpiNNaker core handling the population) +//! \param[out] neuron_id: The ID of the neuron within the subpopulation +//! \param[out] spike: The spike that made this a meaningful choice. +//! This rule synthesises this. +//! \param[out] m_pop_index: The master population table index. +//! \return True if a choice was made +static inline bool potential_presynaptic_partner( + UNUSED uint32_t time, uint32_t *restrict population_id, + uint32_t *restrict sub_population_id, uint32_t *restrict neuron_id, + spike_t *restrict spike, uint32_t *restrict m_pop_index) { + extern rewiring_data_t rewiring_data; + extern pre_pop_info_table_t pre_info; + + uint32_t pop_id = ulrbits(mars_kiss64_seed(rewiring_data.local_seed)) * + pre_info.no_pre_pops; + *population_id = pop_id; + pre_info_t *preapppop_info = pre_info.prepop_info[pop_id]; + + // Select presynaptic sub-population + uint32_t n_id = ulrbits(mars_kiss64_seed(rewiring_data.local_seed)) * + preapppop_info->total_no_atoms; + uint32_t subpop_id = 0; + uint32_t sum = 0; + for (uint32_t i = 0; i < preapppop_info->no_pre_vertices; i++) { + sum += preapppop_info->key_atom_info[i].n_atoms; + if (sum >= n_id) { + subpop_id = i; + break; + } + } + *sub_population_id = subpop_id; + + // Select a presynaptic neuron ID + n_id = ulrbits(mars_kiss64_seed(rewiring_data.local_seed)) * + preapppop_info->key_atom_info[subpop_id].n_atoms; + + *neuron_id = n_id; + *spike = preapppop_info->key_atom_info[subpop_id].key | n_id; + *m_pop_index = preapppop_info->key_atom_info[subpop_id].m_pop_index; + return true; +} + +#endif // _RANDOM_SELECTION_IMPL_H_ diff --git a/neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis/sp_structs.h b/neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis/sp_structs.h new file mode 100644 index 00000000000..15be5f64363 --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis/sp_structs.h @@ -0,0 +1,295 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \dir +//! \brief Structural plasticity through formation and elimination of synapses +//! \file +//! \brief Miscellaneous structures +#ifndef _SP_STRUCTS_H_ +#define _SP_STRUCTS_H_ + +#include +#include +#include +#include + +// Define the formation and elimination params +struct elimination_params; +struct formation_params; + +//! Flag: Is connection lateral? +#define IS_CONNECTION_LAT 1 + +//! Entry of map from post-connection to pre-connection neural indices +typedef struct post_to_pre_entry { + uint8_t pop_index; + uint8_t sub_pop_index; + uint16_t neuron_index; +} post_to_pre_entry; + +//! information per atom +typedef struct { + uint32_t key; + uint32_t mask; + uint32_t n_atoms; + uint32_t lo_atom; + uint32_t m_pop_index; +} key_atom_info_t; + +//! individual pre-synaptic sub-population information +typedef struct { + uint16_t no_pre_vertices; + uint16_t sp_control; + uint16_t delay_lo; + uint16_t delay_hi; + uint32_t weight; + uint32_t connection_type; + uint32_t total_no_atoms; + key_atom_info_t key_atom_info[]; +} pre_info_t; + +//! table of individual pre-synaptic information +typedef struct { + uint32_t no_pre_pops; + pre_info_t **prepop_info; +} pre_pop_info_table_t; + +//! parameters of the synaptic rewiring model +typedef struct { + uint32_t fast; + uint32_t p_rew; + uint32_t s_max; + uint32_t app_no_atoms; + uint32_t machine_no_atoms; + uint32_t low_atom; + uint32_t high_atom; + uint32_t with_replacement; + // the 2 seeds that are used: shared for sync, local for everything else + mars_kiss64_seed_t shared_seed; + mars_kiss64_seed_t local_seed; + uint32_t no_pre_pops; +} rewiring_data_t; + +//! struct representing the current state of rewiring +typedef struct { + //! Seed referenced from rewiring data + mars_kiss64_seed_t *local_seed; + //! Low atom copied from rewiring data + uint32_t post_low_atom; + // with_replacement copied from rewiring data + uint32_t with_replacement; + // what are the currently selecting pre- and post-synaptic neurons + uint32_t pre_syn_id; + uint32_t post_syn_id; + //! does the connection already exist + uint32_t element_exists; + // information extracted from the post to pre table + post_to_pre_entry *post_to_pre_table_entry; + pre_info_t *pre_population_info; + key_atom_info_t *key_atom_info; + post_to_pre_entry post_to_pre; + //! offset in synaptic row (if exists) + uint32_t offset; + //! current delay (if exists) + uint16_t delay; + //! current weight (if exists) + uint16_t weight; + //! synapse type + uint32_t synapse_type; +} current_state_t; + +//! Get a random unsigned integer up to (but not including) a given maximum +//! \param[in] max The maximum value allowed +//! \param[in] seed The random seed to use +//! \return The generated value +static inline uint32_t rand_int(uint32_t max, mars_kiss64_seed_t seed) { + return muliulr(max, ulrbits(mars_kiss64_seed(seed))); +} + +//! \brief unpack the spike into key and identifying information for the +//! neuron; Identify pop, sub-population and low and high atoms +//! \param[in] pre_pop_info_table: The prepopulation information table +//! \param[in] spike: The spike to look up the information from +//! \param[out] neuron_id: The ID of the neuron within its population +//! \param[out] population_id: The population ID +//! \param[out] sub_population_id: The ID of the sub-population +//! \param[out] m_pop_index: The master population table index +//! \return True if the information was found. +static inline bool sp_structs_find_by_spike( + const pre_pop_info_table_t *pre_pop_info_table, spike_t spike, + uint32_t *restrict neuron_id, uint32_t *restrict population_id, + uint32_t *restrict sub_population_id, uint32_t *restrict m_pop_index) { + // Amazing linear search inc. + // Loop over all populations + for (uint32_t i = 0; i < pre_pop_info_table->no_pre_pops; i++) { + const pre_info_t *pre_pop_info = pre_pop_info_table->prepop_info[i]; + + // Loop over all sub-populations and check if the KEY matches + // (with neuron ID masked out) + for (int j = 0; j < pre_pop_info->no_pre_vertices; j++) { + const key_atom_info_t *kai = &pre_pop_info->key_atom_info[j]; + if ((spike & kai->mask) == kai->key) { + *population_id = i; + *sub_population_id = j; + *neuron_id = spike & ~kai->mask; + *m_pop_index = kai->m_pop_index; + return true; + } + } + } + return false; +} + +//! \brief Get the sub-population id and sub-population-based neuron id given +//! the population id and the population-based neuron id +//! \param[in] pre_pop_info_table: The prepopulation information table +//! \param[in] population_id: The population ID +//! \param[in] pop_neuron_id: The ID of the neuron within the population +//! \param[out] sub_population_id: The ID of the sub-population +//! \param[out] sub_pop_neuron_id: +//! The ID of the neuron within the sub-population +//! \param[out] spike: The spike associated with communication from that neuron +//! \return True if the information was found. +static inline bool sp_structs_get_sub_pop_info( + const pre_pop_info_table_t *pre_pop_info_table, uint32_t population_id, + uint32_t pop_neuron_id, uint32_t *restrict sub_population_id, + uint32_t *restrict sub_pop_neuron_id, uint32_t *restrict spike) { + const pre_info_t *app_pop_info = + pre_pop_info_table->prepop_info[population_id]; + uint32_t neuron_id = pop_neuron_id; + for (uint32_t i = 0; i < app_pop_info->no_pre_vertices; i++) { + uint32_t n_atoms = app_pop_info->key_atom_info[i].n_atoms; + if (neuron_id < n_atoms) { + *sub_population_id = i; + *sub_pop_neuron_id = neuron_id; + *spike = app_pop_info->key_atom_info[i].key | neuron_id; + return true; + } + neuron_id -= n_atoms; + } + return false; +} + +//! \brief Removes a synapse from the relevant structures +//! \param[in,out] current_state: Describes what is to be done +//! \param[in,out] row: The row of the synaptic matrix to be updated +//! \return True if the synapse was removed +static inline bool sp_structs_remove_synapse( + current_state_t *restrict current_state, synaptic_row_t restrict row) { + if (!synapse_dynamics_remove_neuron(current_state->offset, row)) { + return false; + } + current_state->post_to_pre_table_entry->neuron_index = 0xFFFF; + return true; +} + +//! \brief Adds a synapse to the relevant structures +//! \param[in,out] current_state: Describes what is to be done +//! \param[in,out] row: The row of the synaptic matrix to be updated +//! \return True if the synapse was added +static inline bool sp_structs_add_synapse( + current_state_t *restrict current_state, synaptic_row_t restrict row) { + uint32_t appr_scaled_weight = current_state->pre_population_info->weight; + + uint32_t actual_delay; + uint32_t offset = current_state->pre_population_info->delay_hi - + current_state->pre_population_info->delay_lo; + actual_delay = rand_int(offset, *(current_state->local_seed)) + + current_state->pre_population_info->delay_lo; + + if (!synapse_dynamics_add_neuron( + current_state->post_syn_id, row, appr_scaled_weight, actual_delay, + current_state->pre_population_info->connection_type)) { + return false; + } + + // Critical: tell the compiler that this pointer is aligned so it doesn't + // internally convert the assignment to a memcpy(), which is a saving of + // hundreds of bytes... + post_to_pre_entry *ppentry = __builtin_assume_aligned( + current_state->post_to_pre_table_entry, 4); + *ppentry = current_state->post_to_pre; + return true; +} + +//! \brief Common code for structural plasticity initialisation. +//! \param[in] sdram_sp_address: Address of the configuration region. +//! \param[in,out] rewiring_data: +//! Address of the rewiring information structure to fill out. +//! \param[in,out] pre_info: +//! The pre-population information structure to fill out. +//! \param[out] post_to_pre_table: Variable to receive the address of the +//! post-population-to-pre-population mapping table that this function +//! discovers in the configuration region. +//! \return pointer to the next piece of memory after the common section of the +//! configuration region. +static inline uint8_t *sp_structs_read_in_common( + address_t sdram_sp_address, rewiring_data_t *rewiring_data, + pre_pop_info_table_t *pre_info, + post_to_pre_entry **post_to_pre_table) { + uint8_t *data = (uint8_t *) sdram_sp_address; + spin1_memcpy(rewiring_data, data, sizeof(rewiring_data_t)); + data += sizeof(rewiring_data_t); + log_debug("Topographic Map Impl, s_max=%u", rewiring_data->s_max); + + pre_info->no_pre_pops = rewiring_data->no_pre_pops; + log_debug(" no pre pops = %d", pre_info->no_pre_pops); + pre_info->prepop_info = spin1_malloc( + rewiring_data->no_pre_pops * sizeof(pre_info_t *)); + if (pre_info->prepop_info == NULL) { + log_error("Could not initialise pre population info"); + rt_error(RTE_SWERR); + } + for (uint32_t i = 0; i < rewiring_data->no_pre_pops; i++) { + pre_info->prepop_info[i] = (pre_info_t *) data; + uint32_t pre_size = (pre_info->prepop_info[i]->no_pre_vertices + * sizeof(key_atom_info_t)) + sizeof(pre_info_t); + pre_info->prepop_info[i] = spin1_malloc(pre_size); + if (pre_info->prepop_info[i] == NULL) { + log_error("Could not initialise pre population info %d", i); + rt_error(RTE_SWERR); + } + spin1_memcpy(pre_info->prepop_info[i], data, pre_size); + + log_debug("no_pre = %u, sp_control %u, " + "delay lo %u, delay hi %u, weight %d", + pre_info->prepop_info[i]->no_pre_vertices, + pre_info->prepop_info[i]->sp_control, + pre_info->prepop_info[i]->delay_lo, + pre_info->prepop_info[i]->delay_hi, + pre_info->prepop_info[i]->weight); + log_debug("connection_type = %d, total_no_atoms=%d", + pre_info->prepop_info[i]->connection_type, + pre_info->prepop_info[i]->total_no_atoms); + data += pre_size; + } + + *post_to_pre_table = (post_to_pre_entry *) data; + uint32_t n_elements = + rewiring_data->s_max * rewiring_data->machine_no_atoms; + + for (uint32_t i=0; i < n_elements; i++){ + log_debug("index %d, pop index %d, sub pop index %d, neuron_index %d", + i, post_to_pre_table[i]->pop_index, + post_to_pre_table[i]->sub_pop_index, + post_to_pre_table[i]->neuron_index); + } + data += n_elements * sizeof(post_to_pre_entry); + return (uint8_t *) data; +} + +#endif // _SP_STRUCTS_H_ diff --git a/neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis/topographic_map_impl.c b/neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis/topographic_map_impl.c new file mode 100644 index 00000000000..3a915bfb3af --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis/topographic_map_impl.c @@ -0,0 +1,328 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/*! \file + * \brief This file contains the main functions for probabilistic + * synaptogenesis. + * + * \author Petrut Bogdan + */ +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include + +// Interface for rules +#include "partner_selection/partner.h" +#include "elimination/elimination.h" +#include "formation/formation.h" + +//----------------------------------------------------------------------------- +// Structures and global data | +//----------------------------------------------------------------------------- + +//! the instantiation of the rewiring data +rewiring_data_t rewiring_data; + +//! inverse of synaptic matrix +static post_to_pre_entry *post_to_pre_table; + +//! pre-population information table +pre_pop_info_table_t pre_info; + +//! The formation parameters per pre-population +static formation_params_t **formation_params; + +//! The elimination parameters per pre-population +static elimination_params_t **elimination_params; + +//! \brief Current states in use. +//! +//! synaptogenesis_row_restructure() moves states from here to ::free_states +static circular_buffer current_state_queue; + +//! \brief Free current states. +//! +//! synaptogenesis_dynamics_rewire() moves states from here to +//! ::current_state_queue +static circular_buffer free_states; + +void print_post_to_pre_entry(void) { + uint32_t n_elements = + rewiring_data.s_max * rewiring_data.machine_no_atoms; + + for (uint32_t i=0; i < n_elements; i++) { + log_debug("index %d, pop index %d, sub pop index %d, neuron_index %d", + i, post_to_pre_table[i].pop_index, + post_to_pre_table[i].sub_pop_index, + post_to_pre_table[i].neuron_index); + } +} + +//----------------------------------------------------------------------------- +// Access helpers for circular buffers +//----------------------------------------------------------------------------- +static inline void _queue_state(current_state_t *state) { + if (__builtin_expect( + !circular_buffer_add(current_state_queue, (uint32_t) state), 0)) { + log_error("Could not add state (0x%08x) to queued states", state); + rt_error(RTE_SWERR); + } +} + +static inline current_state_t *_get_state(void) { + current_state_t *state; + if (__builtin_expect( + !circular_buffer_get_next(current_state_queue, (uint32_t *) &state), + 0)) { + log_error("Could not read a state!"); + rt_error(RTE_SWERR); + } + return state; +} + +static inline void _free_state(current_state_t *state) { + if (__builtin_expect( + !circular_buffer_add(free_states, (uint32_t) state), 0)) { + log_error("Could not add state (0x%08x) to free states", state); + rt_error(RTE_SWERR); + } +} + +static inline current_state_t *_alloc_state(void) { + current_state_t *state; + if (__builtin_expect( + !circular_buffer_get_next(free_states, (uint32_t *) &state), 0)) { + log_error("Ran out of states!"); + rt_error(RTE_SWERR); + } + return state; +} + +//----------------------------------------------------------------------------- +// Initialisation | +//----------------------------------------------------------------------------- + +bool synaptogenesis_dynamics_initialise(address_t sdram_sp_address) { + log_debug("SR init."); + + uint8_t *data = sp_structs_read_in_common( + sdram_sp_address, &rewiring_data, &pre_info, &post_to_pre_table); + + // Allocate current states + uint32_t n_states = 1; + if (rewiring_data.fast) { + n_states = rewiring_data.p_rew; + } + log_debug("Rewiring period %u, fast=%u, n_states=%u", + rewiring_data.p_rew, rewiring_data.fast, n_states); + // Add one to number of states as buffer wastes an entry + current_state_queue = circular_buffer_initialize(n_states + 1); + if (current_state_queue == NULL) { + log_error("Could not allocate current state queue"); + rt_error(RTE_SWERR); + } + // Add one to number of states as buffer wastes an entry + free_states = circular_buffer_initialize(n_states + 1); + if (free_states == NULL) { + log_error("Could not allocate free state queue"); + } + current_state_t *states = spin1_malloc(n_states * sizeof(current_state_t)); + if (states == NULL) { + log_error("Could not allocate states"); + rt_error(RTE_SWERR); + } + for (uint32_t i = 0; i < n_states; i++) { + _free_state(&states[i]); + } + + partner_init(&data); + + formation_params = spin1_malloc( + rewiring_data.no_pre_pops * sizeof(struct formation_params *)); + if (formation_params == NULL) { + log_error("Could not initialise formation parameters"); + rt_error(RTE_SWERR); + } + for (uint32_t i = 0; i < rewiring_data.no_pre_pops; i++) { + formation_params[i] = synaptogenesis_formation_init(&data); + } + + elimination_params = spin1_malloc( + rewiring_data.no_pre_pops * sizeof(struct elimination_params *)); + if (elimination_params == NULL) { + log_error("Could not initialise elimination parameters"); + rt_error(RTE_SWERR); + } + for (uint32_t i = 0; i < rewiring_data.no_pre_pops; i++) { + elimination_params[i] = synaptogenesis_elimination_init(&data); + } + + return true; +} + +bool synaptogenesis_dynamics_rewire( + uint32_t time, spike_t *spike, synaptic_row_t *synaptic_row, + uint32_t *n_bytes) { + + // Randomly choose a postsynaptic (application neuron) + uint32_t post_id = rand_int(rewiring_data.app_no_atoms, + rewiring_data.shared_seed); + + // Check if neuron is in the current machine vertex + if (post_id < rewiring_data.low_atom || + post_id > rewiring_data.high_atom) { + return false; + } + post_id -= rewiring_data.low_atom; + + // Select an arbitrary synaptic element for the neurons + uint32_t row_offset = post_id * rewiring_data.s_max; + uint32_t column_offset = rand_int(rewiring_data.s_max, + rewiring_data.local_seed); + uint32_t total_offset = row_offset + column_offset; + post_to_pre_entry entry = post_to_pre_table[total_offset]; + uint32_t pre_app_pop = 0, pre_sub_pop = 0, m_pop_index = 0, neuron_id = 0; + if (entry.neuron_index == 0xFFFF) { + if (!potential_presynaptic_partner(time, &pre_app_pop, &pre_sub_pop, + &neuron_id, spike, &m_pop_index)) { + return false; + } + } else { + pre_app_pop = entry.pop_index; + pre_sub_pop = entry.sub_pop_index; + neuron_id = entry.neuron_index; + } + pre_info_t *prepop_info = pre_info.prepop_info[pre_app_pop]; + key_atom_info_t *key_atom_info = &prepop_info->key_atom_info[pre_sub_pop]; + if (entry.neuron_index != 0xFFFF) { + *spike = key_atom_info->key | neuron_id; + m_pop_index = key_atom_info->m_pop_index; + } + + if (!population_table_get_first_address(*spike, synaptic_row, n_bytes)) { + log_error("FAIL@key %d", *spike); + rt_error(RTE_SWERR); + } + uint32_t index = 0; + while (index < m_pop_index) { + if (!population_table_get_next_address(spike, synaptic_row, n_bytes)) { + log_error("FAIL@key %d, index %d (failed at %d)", + *spike, m_pop_index, index); + rt_error(RTE_SWERR); + } + index++; + } + + // Saving current state + current_state_t *current_state = _alloc_state(); + current_state->pre_syn_id = neuron_id; + current_state->post_syn_id = post_id; + current_state->element_exists = entry.neuron_index != 0xFFFF; + current_state->post_to_pre_table_entry = &post_to_pre_table[total_offset]; + current_state->pre_population_info = prepop_info; + current_state->key_atom_info = key_atom_info; + current_state->post_to_pre.neuron_index = neuron_id; + current_state->post_to_pre.pop_index = pre_app_pop; + current_state->post_to_pre.sub_pop_index = pre_sub_pop; + current_state->local_seed = &rewiring_data.local_seed; + current_state->post_low_atom = rewiring_data.low_atom; + current_state->with_replacement = rewiring_data.with_replacement; + _queue_state(current_state); + return true; +} + +//! \brief Performs the actual restructuring of a row +//! \details Supporting function for synaptogenesis_row_restructure() +//! \param[in] time: The time of the restructure +//! \param[in] row: The row to restructure +//! \param[in] current_state: The current state of the world +//! \return True if the row was changed and needs to be written back +static inline bool row_restructure( + uint32_t time, synaptic_row_t restrict row, + current_state_t *restrict current_state) { + // the selected pre- and postsynaptic IDs are in current_state + if (current_state->element_exists) { + // find the offset of the neuron in the current row + if (!synapse_dynamics_find_neuron( + current_state->post_syn_id, row, + ¤t_state->weight, ¤t_state->delay, + ¤t_state->offset, ¤t_state->synapse_type)) { + log_debug("Post neuron %u not in row", current_state->post_syn_id); + return false; + } + return synaptogenesis_elimination_rule(current_state, + elimination_params[current_state->post_to_pre.pop_index], + time, row); + } else { + // Can't form if the row is full + uint32_t no_elems = synapse_dynamics_n_connections_in_row( + synapse_row_fixed_region(row)); + if (no_elems >= rewiring_data.s_max) { + log_debug("row is full"); + return false; + } else { + if (current_state->with_replacement) { + // A synapse can be added anywhere on the current row, so just do it + return synaptogenesis_formation_rule(current_state, + formation_params[current_state->post_to_pre.pop_index], time, row); + } else { + // A synapse cannot be added if one exists between the current pair of neurons + if (!synapse_dynamics_find_neuron( + current_state->post_syn_id, row, + &(current_state->weight), &(current_state->delay), + &(current_state->offset), &(current_state->synapse_type))) { + return synaptogenesis_formation_rule(current_state, + formation_params[current_state->post_to_pre.pop_index], time, row); + } else { + log_debug("Post neuron %u already in row", current_state->post_syn_id); + return false; + } + } + } + } +} + +bool synaptogenesis_row_restructure(uint32_t time, synaptic_row_t row) { + current_state_t *current_state = _get_state(); + bool return_value = row_restructure(time, row, current_state); + _free_state(current_state); + return return_value; +} + +int32_t synaptogenesis_rewiring_period(void) { + return rewiring_data.p_rew; +} + +bool synaptogenesis_is_fast(void) { + return rewiring_data.fast == 1; +} + +void synaptogenesis_spike_received(uint32_t time, spike_t spike) { + partner_spike_received(time, spike); +} diff --git a/neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis_dynamics.h b/neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis_dynamics.h new file mode 100644 index 00000000000..8edd3777b6a --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis_dynamics.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/*! + * \dir + * \brief Structural plasticity interface and algorithms + * \file + * \brief This file contains the main interface for structural plasticity + * \author Petrut Bogdan + */ +#ifndef _SYNAPTOGENESIS_DYNAMICS_H_ +#define _SYNAPTOGENESIS_DYNAMICS_H_ + +#include + +//! \brief Initialisation of synaptic rewiring (synaptogenesis) +//! parameters (random seed, spread of receptive field etc.) +//! \param[in] sdram_sp_address: Address of the start of the SDRAM region +//! which contains synaptic rewiring params. +//! \return Whether we were successful. +bool synaptogenesis_dynamics_initialise( + address_t sdram_sp_address); + +//! \brief Trigger the process of synaptic rewiring +//! \details Usually called on a timer registered in c_main() +//! \param[in] time: the current timestep +//! \param[out] spike: variable to hold the spike +//! \param[out] synaptic_row: variable to hold the address of the row +//! \param[out] n_bytes: variable to hold the size of the row +//! \return True if a row is to be transferred, false otherwise +bool synaptogenesis_dynamics_rewire(uint32_t time, + spike_t *spike, synaptic_row_t *synaptic_row, uint32_t *n_bytes); + +//! \brief Perform the actual restructuring of a row +//! \param[in] time: The time of the restructure +//! \param[in] row: The row to restructure +//! \return True if the row was changed and needs to be written back +bool synaptogenesis_row_restructure(uint32_t time, synaptic_row_t row); + +//! \brief Get the period of rewiring +//! \return Based on synaptogenesis_is_fast(), this can either be how many times +//! rewiring happens in a timestep, or how many timesteps have to pass until +//! rewiring happens. +int32_t synaptogenesis_rewiring_period(void); + +//! \brief Get whether rewiring is attempted multiple times per timestep +//! or after a number of timesteps. +//! \return true if the result of synaptogenesis_rewiring_period() is the number +//! of attempts to try per timestep. +bool synaptogenesis_is_fast(void); + +//! \brief Indicates that a spike has been received +//! \param[in] time: The time that the spike was received at +//! \param[in] spike: The received spike +void synaptogenesis_spike_received(uint32_t time, spike_t spike); + +//! Print a certain data object +void print_post_to_pre_entry(void); + +#endif // _SYNAPTOGENESIS_DYNAMICS_H_ diff --git a/neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis_dynamics_static_impl.c b/neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis_dynamics_static_impl.c new file mode 100644 index 00000000000..7e188945fe0 --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/structural_plasticity/synaptogenesis_dynamics_static_impl.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/*! + * \file + * \brief This file contains the static (non-)implementation of synaptogenesis. + * \details No functionality is gained with this class. + */ +#include "synaptogenesis_dynamics.h" +#include + +bool synaptogenesis_dynamics_initialise(UNUSED address_t sdram_sp_address) { + return true; +} + +bool synaptogenesis_dynamics_rewire( + UNUSED uint32_t time, UNUSED spike_t *spike, + UNUSED synaptic_row_t *synaptic_row, UNUSED uint32_t *n_bytes) { + return false; +} + +bool synaptogenesis_row_restructure( + UNUSED uint32_t time, UNUSED synaptic_row_t row) { + return false; +} + +int32_t synaptogenesis_rewiring_period(void) { + return -1; +} + +bool synaptogenesis_is_fast(void) { + return false; +} + +void synaptogenesis_spike_received(UNUSED uint32_t time, UNUSED spike_t spike) { +} + +void print_post_to_pre_entry(void) { + return; +} diff --git a/neural_modelling/src/meanfield_fixing/synapse_row.h b/neural_modelling/src/meanfield_fixing/synapse_row.h new file mode 100644 index 00000000000..979a0fbe047 --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/synapse_row.h @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/*! + * \file + * \brief implementation for handling the processing of synapse rows. + * + * \section row Synapse Row Representation + * ``` + * | Weight | Delay | Synapse Type | Neuron Index | + * |-------------------|------------------|-----------------|------------------| + * |SYNAPSE_WEIGHT_BITS|SYNAPSE_DELAY_BITS|SYNAPSE_TYPE_BITS|SYNAPSE_INDEX_BITS| + * | | | SYNAPSE_TYPE_INDEX_BITS | + * ``` + * The API interface supports: + * + * - synapse_row_plastic_size() + * - synapse_row_plastic_region() + * - synapse_row_fixed_region() + * - synapse_row_num_fixed_synapses() + * - synapse_row_num_plastic_controls() + * - synapse_row_plastic_controls() + * - synapse_row_fixed_weight_controls() + * - synapse_row_sparse_index() + * - synapse_row_sparse_type() + * - synapse_row_sparse_type_index() + * - synapse_row_sparse_delay() + * - synapse_row_sparse_weight() + * + * \section matrix Data Structure + * + * The data structure layout supported by this API is designed for + * mixed plastic and fixed synapse rows. + * + * The data structure is treated as an array of 32-bit words. + * Special meanings are ascribed to the 0th and 1st elements + * of the array. + * + * We are expecting the original source address in SDRAM to be + * in row[0]. The number of array elements in the plastic + * region is held in the upper part of row[1]. A tag to indicate + * the nature of the synaptic row structure is held in the lower + * part of row[1]. + * ``` + * 0: [ N = | ] + * 1: [ First word of plastic region ] + * ... + * N: [ Last word of plastic region ] + * N+1: [ First word of fixed region ] + * ... + * M: [ Last word of fixed region ] + * ``` + * + * \section fixed Fixed and Fixed-Plastic Regions + * + * Within the fixed-region extracted using the above API, fixed[0] + * contains the number of 32-bit fixed synaptic words, fixed[1] + * contains the number of 16-bit plastic synapse control words. + * (The weights for the plastic synapses are assumed to be stored + * in some learning-rule-specific format in the plastic region) + * ``` + * 0: [ F = Num fixed synapses ] + * 1: [ P = Size of plastic region in HALF-WORDS ] + * 2: [ First fixed synaptic word ] + * ... + * F+1: [ Last fixed synaptic word ] + * F+2: [ 1st plastic synapse control word|2nd plastic control word ] + * ... + * F+1+ceil(P/2): [ Last word of fixed region ] + * ``` + * Note that \p P is effectively rounded up to a multiple of two for storage + * purposes. + */ + +#ifndef _SYNAPSE_ROW_H_ +#define _SYNAPSE_ROW_H_ + +#include + +//! how many bits the synapse weight will take +#ifndef SYNAPSE_WEIGHT_BITS +#define SYNAPSE_WEIGHT_BITS 16 +#endif + +//! how many bits the synapse delay will take +#ifndef SYNAPSE_DELAY_BITS +#define SYNAPSE_DELAY_BITS 4 +#endif + +// Create some masks based on the number of bits +//! the mask for the synapse delay in the row +#define SYNAPSE_DELAY_MASK ((1 << SYNAPSE_DELAY_BITS) - 1) + +#ifdef SYNAPSE_WEIGHTS_SIGNED +//! Define the type of the weights +typedef __int_t(SYNAPSE_WEIGHT_BITS) weight_t; +#else +//! Define the type of the weights +typedef __uint_t(SYNAPSE_WEIGHT_BITS) weight_t; +#endif +//! Define the type of the control data +typedef uint16_t control_t; + +//! Number of header words per synaptic row +#define N_SYNAPSE_ROW_HEADER_WORDS 3 + +//! The type of the plastic-plastic part of the row +typedef struct { + size_t size; //!< The number of plastic words in `data` + uint32_t data[]; //!< The plastic words, followed by the fixed part +} synapse_row_plastic_part_t; + +//! The type of the fixed part of the row. The fixed-plastic part follows. +typedef struct { + size_t num_fixed; //!< The number of fixed synapses in `data` + size_t num_plastic; //!< The number of plastic controls in `data` + uint32_t data[]; //!< The data, first the fixed then the plastic +} synapse_row_fixed_part_t; + +typedef struct synapse_row_plastic_data_t synapse_row_plastic_data_t; + +//! \brief Get the size of the plastic region +//! \param[in] row: The synaptic row +//! \return The size of the plastic region of the row +static inline size_t synapse_row_plastic_size(const synaptic_row_t row) { + const synapse_row_plastic_part_t *the_row = + (const synapse_row_plastic_part_t *) row; + return the_row->size; +} + +//! \brief Get the address of the plastic region +//! \param[in] row: The synaptic row +//! \return Pointer to the plastic region of the row +static inline synapse_row_plastic_data_t *synapse_row_plastic_region( + synaptic_row_t row) { + synapse_row_plastic_part_t *the_row = (synapse_row_plastic_part_t *) row; + return (synapse_row_plastic_data_t *) the_row->data; +} + +//! \brief Get the address of the non-plastic (or fixed) region +//! \param[in] row: The synaptic row +//! \return Address of the fixed region of the row +static inline synapse_row_fixed_part_t *synapse_row_fixed_region( + synaptic_row_t row) { + synapse_row_plastic_part_t *the_row = (synapse_row_plastic_part_t *) row; + return (synapse_row_fixed_part_t *) &the_row->data[the_row->size]; +} + +//! \brief Get the number of fixed synapses in the row +//! \param[in] fixed: The fixed region of the synaptic row +//! \return Size of the fixed region of the row (in words) +static inline size_t synapse_row_num_fixed_synapses( + const synapse_row_fixed_part_t *fixed) { + return fixed->num_fixed; +} + +//! \brief Get the number of plastic controls in the row +//! \param[in] fixed: The fixed region of the synaptic row +//! \return Size of the fixed-plastic region of the row (in _half_ words) +static inline size_t synapse_row_num_plastic_controls( + const synapse_row_fixed_part_t *fixed) { + return fixed->num_plastic; +} + +//! \brief Get the array of plastic controls in the row +//! \param[in] fixed: The fixed region of the synaptic row +//! \return Address of the fixed-plastic region of the row +static inline control_t *synapse_row_plastic_controls( + synapse_row_fixed_part_t *fixed) { + return (control_t *) &fixed->data[fixed->num_fixed]; +} + +//! \brief The array of fixed weights in the row +//! \param[in] fixed: The fixed region of the synaptic row +//! \return Address of the fixed-fixed region of the row +static inline uint32_t *synapse_row_fixed_weight_controls( + synapse_row_fixed_part_t *fixed) { + return fixed->data; +} + +// The following are offset calculations into the ring buffers +//! \brief Get the index +//! \param[in] x: The value to decode +//! \param[in] synapse_index_mask: Mask for the synapse index (depends on type) +//! \return the index +static inline index_t synapse_row_sparse_index( + uint32_t x, uint32_t synapse_index_mask) { + return x & synapse_index_mask; +} + +//! \brief Get the type code +//! \param[in] x: The value to decode +//! \param[in] synapse_index_bits: +//! Number of bits for the synapse index (depends on type) +//! \param[in] synapse_type_mask: Mask for the synapse type (depends on type) +//! \return the type code +static inline index_t synapse_row_sparse_type( + uint32_t x, uint32_t synapse_index_bits, uint32_t synapse_type_mask) { + return (x >> synapse_index_bits) & synapse_type_mask; +} + +//! \brief Get the type and index +//! \param[in] x: The value to decode +//! \param[in] synapse_type_index_mask: +//! Mask for the synapse type and index (depends on type) +//! \return the type and index (packed in the low bits of a word) +static inline index_t synapse_row_sparse_type_index( + uint32_t x, uint32_t synapse_type_index_mask) { + return x & synapse_type_index_mask; +} + +//! \brief Get the delay from an encoded synapse descriptor +//! \param[in] x: The value to decode +//! \param[in] synapse_type_index_bits: +//! Number of bits for the synapse type and index (depends on type) +//! \return the delay +static inline index_t synapse_row_sparse_delay( + uint32_t x, uint32_t synapse_type_index_bits) { + return (x >> synapse_type_index_bits) & SYNAPSE_DELAY_MASK; +} + +//! \brief Get the weight from an encoded synapse descriptor +//! \param[in] x: The value to decode +//! \return the weight +static inline weight_t synapse_row_sparse_weight(uint32_t x) { + return x >> (32 - SYNAPSE_WEIGHT_BITS); +} + +#endif // SYNAPSE_ROW_H diff --git a/neural_modelling/src/meanfield_fixing/synapse_types/synapse_types.h b/neural_modelling/src/meanfield_fixing/synapse_types/synapse_types.h new file mode 100644 index 00000000000..6ab49058f33 --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/synapse_types/synapse_types.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \dir +//! \brief Synaptic behaviour types +//! \file +//! \brief API for synaptic behaviour types +//! (see also \ref src/neuron/input_types) +#ifndef _SYNAPSE_TYPES_H_ +#define _SYNAPSE_TYPES_H_ + +#include +#include + +// Forward declaration of real type +struct synapse_param_t; +typedef struct synapse_param_t synapse_param_t; + +//! Forward declaration of synapse type (creates a definition for a pointer +//! to a synapse type parameter struct +typedef synapse_param_t *synapse_param_pointer_t; + +//! \brief decays the stuff thats sitting in the input buffers +//! as these have not yet been processed and applied to the neuron. +//! +//! This is to compensate for the valve behaviour of a synapse +//! in biology (spike goes in, synapse opens, then closes slowly). +//! \param[in,out] parameters: the parameters to update +static void synapse_types_shape_input(synapse_param_t *parameters); + +//! \brief adds the inputs for a give timer period to a given neuron that is +//! being simulated by this model +//! \param[in] synapse_type_index: the type of input that this input is to be +//! considered (aka excitatory or inhibitory etc) +//! \param[in,out] parameters: the parameters to update +//! \param[in] input: the inputs for that given synapse_type. +static void synapse_types_add_neuron_input( + index_t synapse_type_index, synapse_param_t *parameters, + input_t input); + +//! \brief extracts the excitatory input buffers from the buffers available +//! for a given neuron ID +//! \param[in] parameters: the pointer to the parameters to use +//! \return Pointer to array of excitatory input buffers for a given neuron ID. +static input_t* synapse_types_get_excitatory_input( + input_t *excitatory_response, synapse_param_t *parameters); + +//! \brief extracts the inhibitory input buffers from the buffers available +//! for a given neuron ID +//! \param[in] parameters: the pointer to the parameters to use +//! \return Pointer to array of inhibitory input buffers for a given neuron ID. +static input_t* synapse_types_get_inhibitory_input( + input_t *inhibitory_response, synapse_param_t *parameters); + +//! \brief returns a human readable character for the type of synapse. +//! +//! Examples would be `X` = excitatory types, `I` = inhibitory types, etc. +//! +//! \param[in] synapse_type_index: the synapse type index +//! (there is a specific index interpretation in each synapse type) +//! \return a human readable character representing the synapse type. +static const char *synapse_types_get_type_char(index_t synapse_type_index); + +//! \brief prints the parameters of the synapse type +//! \param[in] parameters: the pointer to the parameters to print +static void synapse_types_print_parameters( + synapse_param_t *parameters); + +//! \brief prints the input for a neuron ID given the available inputs +//! currently only executed when the models are in debug mode, as the prints +//! are controlled from the synapses.c print_inputs() method. +//! \param[in] parameters: the pointer to the parameters to print +static void synapse_types_print_input(synapse_param_t *parameters); + +#endif // _SYNAPSE_TYPES_H_ diff --git a/neural_modelling/src/meanfield_fixing/synapse_types/synapse_types_alpha_impl.h b/neural_modelling/src/meanfield_fixing/synapse_types/synapse_types_alpha_impl.h new file mode 100644 index 00000000000..6486b5ed295 --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/synapse_types/synapse_types_alpha_impl.h @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/*! + * \file + * \brief implementation of synapse_types.h for an alpha synapse behaviour + */ + +#ifndef _ALPHA_SYNAPSE_H_ +#define _ALPHA_SYNAPSE_H_ + +//--------------------------------------- +// Macros +//--------------------------------------- +//! \brief Number of bits to encode the synapse type +//! \details ceil(log2(#SYNAPSE_TYPE_COUNT)) +#define SYNAPSE_TYPE_BITS 1 +//! \brief Number of synapse types +//! \details #NUM_EXCITATORY_RECEPTORS + #NUM_INHIBITORY_RECEPTORS +#define SYNAPSE_TYPE_COUNT 2 + +//! Number of excitatory receptors +#define NUM_EXCITATORY_RECEPTORS 1 +//! Number of inhibitory receptors +#define NUM_INHIBITORY_RECEPTORS 1 + +#include +#include +#include "synapse_types.h" + +//--------------------------------------- +// Synapse parameters +//--------------------------------------- +//! Internal structure of an alpha-shaped synaptic input +typedef struct alpha_params_t { + input_t lin_buff; //!< buffer for linear term + input_t exp_buff; //!< buffer for exponential term + //! _τ_-1 pre-multiplied by dt + input_t dt_divided_by_tau_sqr; + decay_t decay; //!< Exponential decay multiplier + input_t q_buff; //!< Temporary value of input +} alpha_params_t; + +struct synapse_param_t { + alpha_params_t exc; //!< Excitatory synaptic input + alpha_params_t inh; //!< Inhibitory synaptic input +}; + +//! The supported synapse type indices +typedef enum { + EXCITATORY, //!< Excitatory synaptic input + INHIBITORY, //!< Inhibitory synaptic input +} synapse_alpha_input_buffer_regions; + +//--------------------------------------- +// Synapse shaping inline implementation +//--------------------------------------- + +//! \brief Applies alpha shaping to a parameter +//! \param[in,out] a_params: The parameter to shape +static inline void alpha_shaping(alpha_params_t* a_params) { + a_params->lin_buff = a_params->lin_buff + ( + a_params->q_buff * a_params->dt_divided_by_tau_sqr); + + // Update exponential buffer + a_params->exp_buff = decay_s1615(a_params->exp_buff, a_params->decay); +} + +//! \brief decays the stuff thats sitting in the input buffers as these have not +//! yet been processed and applied to the neuron. +//! +//! This is to compensate for the valve behaviour of a synapse in biology +//! (spike goes in, synapse opens, then closes slowly) +//! plus the leaky aspect of a neuron. +//! +//! \param[in,out] parameters: the parameters to update +static inline void synapse_types_shape_input( + synapse_param_t *parameters) { + alpha_shaping(¶meters->exc); + alpha_shaping(¶meters->inh); +#if 0 + log_debug("lin: %12.6k, exp: %12.6k, comb: %12.6k", + parameters->exc.lin_buff, + parameters->exc.exp_buff, + parameters->exc.lin_buff * parameters->exc.exp_buff); +#endif +} + +//! \brief helper function to add input for a given timer period to a given +//! neuron +//! \param[in] a_params: the parameter to update +//! \param[in] input: the input to add. +static inline void add_input_alpha(alpha_params_t *a_params, input_t input) { + a_params->q_buff = input; + + a_params->exp_buff = + decay_s1615(a_params->exp_buff, a_params->decay) + ONE; + + a_params->lin_buff = + (a_params->lin_buff + (input * a_params->dt_divided_by_tau_sqr)) + * (ONE - ONE/a_params->exp_buff); +} + +//! \brief adds the inputs for a give timer period to a given neuron that is +//! being simulated by this model +//! \details Add input from ring buffer. Zero if no spikes, otherwise one or +//! more weights +//! \param[in] synapse_type_index: the type of input that this input is to be +//! considered (aka excitatory or inhibitory etc) +//! \param[in,out] parameters: the parameters to update +//! \param[in] input: the inputs for that given synapse_type. +static inline void synapse_types_add_neuron_input( + index_t synapse_type_index, synapse_param_t *parameters, + input_t input) { + if (input > ZERO) { + switch (synapse_type_index) { + case EXCITATORY: + add_input_alpha(¶meters->exc, input); + break; + case INHIBITORY: + add_input_alpha(¶meters->inh, input); + break; + } + } +} + +//! \brief extracts the excitatory input buffers from the buffers available +//! for a given neuron ID +//! \param[in] parameters: the pointer to the parameters to use +//! \return Pointer to array of excitatory input buffers for a given neuron ID. +static inline input_t* synapse_types_get_excitatory_input( + input_t *excitatory_response, synapse_param_t *parameters) { + excitatory_response[0] = + parameters->exc.lin_buff * parameters->exc.exp_buff; + return &excitatory_response[0]; +} + +//! \brief extracts the inhibitory input buffers from the buffers available +//! for a given neuron ID +//! \param[in] parameters: the pointer to the parameters to use +//! \return Pointer to array of inhibitory input buffers for a given neuron ID. +static inline input_t* synapse_types_get_inhibitory_input( + input_t *inhibitory_response, synapse_param_t *parameters) { + inhibitory_response[0] = + parameters->inh.lin_buff * parameters->inh.exp_buff; + return &inhibitory_response[0]; +} + +//! \brief returns a human readable character for the type of synapse. +//! \details Examples would be `X` = excitatory types, `I` = inhibitory types, +//! etc. +//! \param[in] synapse_type_index: the synapse type index +//! (there is a specific index interpretation in each synapse type) +//! \return a human readable character representing the synapse type. +static inline const char *synapse_types_get_type_char( + index_t synapse_type_index) { + switch (synapse_type_index) { + case EXCITATORY: + return "X"; + case INHIBITORY: + return "I"; + default: + log_debug("did not recognise synapse type %i", synapse_type_index); + return "?"; + } +} + +//! \brief prints the input for a neuron ID given the available inputs +//! currently only executed when the models are in debug mode, as the prints +//! are controlled from the synapses.c print_inputs() method. +//! \param[in] parameters: the pointer to the parameters to print +static inline void synapse_types_print_input( + synapse_param_t *parameters) { + io_printf(IO_BUF, "%12.6k - %12.6k", + parameters->exc.lin_buff * parameters->exc.exp_buff, + parameters->inh.lin_buff * parameters->inh.exp_buff); +} + +//! \brief prints the parameters of the synapse type +//! \param[in] parameters: the pointer to the parameters to print +static inline void synapse_types_print_parameters(synapse_param_t *parameters) { + log_debug("-------------------------------------\n"); + log_debug("exc_response = %11.4k\n", + parameters->exc.lin_buff * parameters->exc.exp_buff); + log_debug("inh_response = %11.4k\n", + parameters->inh.lin_buff * parameters->inh.exp_buff); +} + +#endif // _ALPHA_SYNAPSE_H_ diff --git a/neural_modelling/src/meanfield_fixing/synapse_types/synapse_types_delta_impl.h b/neural_modelling/src/meanfield_fixing/synapse_types/synapse_types_delta_impl.h new file mode 100644 index 00000000000..1111c9e9793 --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/synapse_types/synapse_types_delta_impl.h @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/*! + * \file + * \brief implementation of synapse_types.h for a delta decay to synapses. + * + * If we have combined excitatory/inhibitory synapses it will be + * because both excitatory and inhibitory synaptic time-constants + * (and thus propagators) are identical. + */ + +#ifndef _SYNAPSE_TYPES_DELTA_IMPL_H_ +#define _SYNAPSE_TYPES_DELTA_IMPL_H_ + +//--------------------------------------- +// Macros +//--------------------------------------- +//! \brief Number of bits to encode the synapse type +//! \details ceil(log2(#SYNAPSE_TYPE_COUNT)) +#define SYNAPSE_TYPE_BITS 1 +//! \brief Number of synapse types +//! \details #NUM_EXCITATORY_RECEPTORS + #NUM_INHIBITORY_RECEPTORS +#define SYNAPSE_TYPE_COUNT 2 + +//! Number of excitatory receptors +#define NUM_EXCITATORY_RECEPTORS 1 +//! Number of inhibitory receptors +#define NUM_INHIBITORY_RECEPTORS 1 + +#include +#include +#include "synapse_types.h" + +//--------------------------------------- +// Synapse parameters +//--------------------------------------- +//! A synaptic input shaped as a Dirac delta +typedef struct delta_params_t { + //! The synaptic input value + input_t synaptic_input_value; +} delta_params_t; + +//! Delta synapses support just a single excitatory and inhibitory input each +struct synapse_param_t { + delta_params_t exc; //!< Excitatory synaptic input + delta_params_t inh; //!< Inhibitory synaptic input +}; + +//! The supported synapse type indices +typedef enum { + EXCITATORY, //!< Excitatory synaptic input + INHIBITORY, //!< Inhibitory synaptic input +} synapse_delta_input_buffer_regions; + +//--------------------------------------- +// Synapse shaping inline implementation +//--------------------------------------- + +//! \brief Decays the stuff thats sitting in the input buffers. +//! \details +//! In this case, a delta shape means returning the value to zero +//! immediately. +//! \param[out] delta_param: the parameter to update +static inline void delta_shaping(delta_params_t *delta_param) { + delta_param->synaptic_input_value = 0; +} + +//! \brief decays the stuff thats sitting in the input buffers as these have not +//! yet been processed and applied to the neuron. +//! +//! This is to compensate for the valve behaviour of a synapse in biology +//! (spike goes in, synapse opens, then closes slowly) +//! plus the leaky aspect of a neuron. +//! +//! \param[in,out] parameters: the pointer to the parameters to use +static inline void synapse_types_shape_input( + synapse_param_t *parameters) { + delta_shaping(¶meters->exc); + delta_shaping(¶meters->inh); +} + +//! \brief helper function to add input for a given timer period to a given +//! neuron +//! \param[in,out] delta_param: the parameter to update +//! \param[in] input: the input to add. +static inline void add_input_delta( + delta_params_t *delta_param, input_t input) { + delta_param->synaptic_input_value += input; +} + +//! \brief adds the inputs for a give timer period to a given neuron that is +//! being simulated by this model +//! \param[in] synapse_type_index the type of input that this input is to be +//! considered (aka excitatory or inhibitory etc) +//! \param[in,out] parameters: the pointer to the parameters to use +//! \param[in] input the inputs for that given synapse_type. +static inline void synapse_types_add_neuron_input( + index_t synapse_type_index, synapse_param_t *parameters, + input_t input) { + switch (synapse_type_index) { + case EXCITATORY: + add_input_delta(¶meters->exc, input); + break; + case INHIBITORY: + add_input_delta(¶meters->inh, input); + break; + } +} + +//! \brief extracts the excitatory input buffers from the buffers available +//! for a given parameter set +//! \param[in] parameters: the pointer to the parameters to use +//! \return the excitatory input buffers for a given neuron ID. +static inline input_t *synapse_types_get_excitatory_input( + input_t *excitatory_response, synapse_param_t *parameters) { + excitatory_response[0] = parameters->exc.synaptic_input_value; + return &excitatory_response[0]; +} + +//! \brief extracts the inhibitory input buffers from the buffers available +//! for a given parameter set +//! \param[in] parameters: the pointer to the parameters to use +//! \return the inhibitory input buffers for a given neuron ID. +static inline input_t *synapse_types_get_inhibitory_input( + input_t *inhibitory_response, synapse_param_t *parameters) { + inhibitory_response[0] = parameters->inh.synaptic_input_value; + return &inhibitory_response[0]; +} + +//! \brief returns a human readable character for the type of synapse. +//! examples would be X = excitatory types, I = inhibitory types etc etc. +//! \param[in] synapse_type_index: the synapse type index +//! (there is a specific index interpretation in each synapse type) +//! \return a human readable character representing the synapse type. +static inline const char *synapse_types_get_type_char( + index_t synapse_type_index) { + switch (synapse_type_index) { + case EXCITATORY: + return "X"; + case INHIBITORY: + return "I"; + default: + log_debug("did not recognise synapse type %i", synapse_type_index); + return "?"; + } +} + +//! \brief prints the input for a neuron ID given the available inputs +//! currently only executed when the models are in debug mode, as the prints +//! are controlled from the synapses.c print_inputs() method. +//! \param[in] parameters: the pointer to the parameters to use +static inline void synapse_types_print_input( + synapse_param_t *parameters) { + io_printf(IO_BUF, "%12.6k - %12.6k", + parameters->exc.synaptic_input_value, + parameters->inh.synaptic_input_value); +} + +//! \brief printer call +//! \param[in] parameters: the pointer to the parameters to print +static inline void synapse_types_print_parameters( + synapse_param_t *parameters) { + synapse_types_print_input(parameters); +} + +#endif // _SYNAPSE_TYPES_DELTA_IMPL_H_ diff --git a/neural_modelling/src/meanfield_fixing/synapse_types/synapse_types_dual_excitatory_exponential_impl.h b/neural_modelling/src/meanfield_fixing/synapse_types/synapse_types_dual_excitatory_exponential_impl.h new file mode 100644 index 00000000000..5160c867a53 --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/synapse_types/synapse_types_dual_excitatory_exponential_impl.h @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/*! + * \file + * \brief implementation of synapse_types.h for a simple duel exponential decay + * to synapses. + * + * \details If we have combined excitatory_one/excitatory_two/inhibitory + * synapses it will be because both excitatory and inhibitory synaptic + * time-constants (and thus propogators) are identical. + */ + +#ifndef _SYNAPSE_TYPES_DUAL_EXCITATORY_EXPONENTIAL_IMPL_H_ +#define _SYNAPSE_TYPES_DUAL_EXCITATORY_EXPONENTIAL_IMPL_H_ + +//--------------------------------------- +// Macros +//--------------------------------------- +//! \brief Number of bits to encode the synapse type +//! \details ceil(log2(#SYNAPSE_TYPE_COUNT)) +#define SYNAPSE_TYPE_BITS 2 +//! \brief Number of synapse types +//! \details #NUM_EXCITATORY_RECEPTORS + #NUM_INHIBITORY_RECEPTORS +#define SYNAPSE_TYPE_COUNT 3 + +//! Number of excitatory receptors +#define NUM_EXCITATORY_RECEPTORS 2 +//! Number of inhibitory receptors +#define NUM_INHIBITORY_RECEPTORS 1 + +#include +#include +#include "synapse_types.h" + +//--------------------------------------- +// Synapse parameters +//--------------------------------------- +//! Parameters for an exponential decay +typedef struct exp_params_t { + decay_t decay; //!< Decay multiplier per timestep + decay_t init; //!< Initial decay factor + input_t synaptic_input_value; //!< The actual synaptic contribution +} exp_params_t; + +struct synapse_param_t { + exp_params_t exc; //!< First excitatory synaptic input + exp_params_t exc2; //!< Second excitatory synaptic input + exp_params_t inh; //!< Inhibitory synaptic input +}; + +//! The supported synapse type indices +typedef enum { + EXCITATORY_ONE, //!< First excitatory synaptic input + EXCITATORY_TWO, //!< Second excitatory synaptic input + INHIBITORY, //!< Inhibitory synaptic input +} synapse_dual_input_buffer_regions; + +//--------------------------------------- +// Synapse shaping inline implementation +//--------------------------------------- + +//! \brief Shapes a single parameter +//! \param[in,out] exp_param: The parameter to shape +static inline void exp_shaping(exp_params_t *exp_param) { + // decay value according to decay constant + exp_param->synaptic_input_value = + decay_s1615(exp_param->synaptic_input_value, exp_param->decay); +} + +//! \brief decays the stuff thats sitting in the input buffers as these have not +//! yet been processed and applied to the neuron. +//! +//! This is to compensate for the valve behaviour of a synapse in biology (spike +//! goes in, synapse opens, then closes slowly) plus the leaky aspect of a +//! neuron. +//! +//! \param[in,out] parameters: the parameters to update +static inline void synapse_types_shape_input(synapse_param_t *parameters) { + exp_shaping(¶meters->exc); + exp_shaping(¶meters->exc2); + exp_shaping(¶meters->inh); +} + +//! \brief helper function to add input for a given timer period to a given +//! neuron +//! \param[in,out] exp_param: the parameter to be updated +//! \param[in] input: the input to add. +static inline void add_input_exp(exp_params_t *exp_param, input_t input) { + exp_param->synaptic_input_value = exp_param->synaptic_input_value + + decay_s1615(input, exp_param->init); +} + +//! \brief adds the inputs for a give timer period to a given neuron that is +//! being simulated by this model +//! \param[in] synapse_type_index: the type of input that this input is to be +//! considered (aka excitatory or inhibitory etc) +//! \param[in,out] parameters: the pointer to the parameters to use +//! \param[in] input: the inputs for that given synapse_type. +static inline void synapse_types_add_neuron_input( + index_t synapse_type_index, synapse_param_t *parameters, + input_t input) { + switch (synapse_type_index) { + case EXCITATORY_ONE: + add_input_exp(¶meters->exc, input); + break; + case EXCITATORY_TWO: + add_input_exp(¶meters->exc2, input); + break; + case INHIBITORY: + add_input_exp(¶meters->inh, input); + break; + } +} + +//! \brief extracts the excitatory input buffers from the buffers available +//! for a given parameter set +//! \param[in] parameters: the pointer to the parameters to use +//! \return the excitatory input buffers for a given neuron ID. +static inline input_t* synapse_types_get_excitatory_input( + input_t *excitatory_response, synapse_param_t *parameters) { + excitatory_response[0] = parameters->exc.synaptic_input_value; + excitatory_response[1] = parameters->exc2.synaptic_input_value; + return &excitatory_response[0]; +} + +//! \brief extracts the inhibitory input buffers from the buffers available +//! for a given parameter set +//! \param[in] parameters: the pointer to the parameters to use +//! \return the inhibitory input buffers for a given neuron ID. +static inline input_t* synapse_types_get_inhibitory_input( + input_t *inhibitory_response, synapse_param_t *parameters) { + inhibitory_response[0] = parameters->inh.synaptic_input_value; + return &inhibitory_response[0]; +} + +//! \brief returns a human readable character for the type of synapse. +//! examples would be X = excitatory types, I = inhibitory types etc etc. +//! \param[in] synapse_type_index: the synapse type index +//! (there is a specific index interpretation in each synapse type) +//! \return a human readable character representing the synapse type. +static inline const char *synapse_types_get_type_char( + index_t synapse_type_index) { + switch (synapse_type_index) { + case EXCITATORY_ONE: + return "X1"; + case EXCITATORY_TWO: + return "X2"; + case INHIBITORY: + return "I"; + default: + log_debug("did not recognise synapse type %i", synapse_type_index); + return "?"; + } +} + +//! \brief prints the input for a neuron ID given the available inputs +//! currently only executed when the models are in debug mode, as the prints +//! are controlled from the synapses.c print_inputs() method. +//! \param[in] parameters: the pointer to the parameters to use +static inline void synapse_types_print_input( + synapse_param_t *parameters) { + io_printf(IO_BUF, "%12.6k + %12.6k - %12.6k", + parameters->exc.synaptic_input_value, + parameters->exc2.synaptic_input_value, + parameters->inh.synaptic_input_value); +} + +//! \brief printer call +//! \param[in] parameters: the pointer to the parameters to print +static inline void synapse_types_print_parameters( + synapse_param_t *parameters) { + log_info("exc_decay = %11.4k\n", parameters->exc.decay); + log_info("exc_init = %11.4k\n", parameters->exc.init); + log_info("exc2_decay = %11.4k\n", parameters->exc2.decay); + log_info("exc2_init = %11.4k\n", parameters->exc2.init); + log_info("inh_decay = %11.4k\n", parameters->inh.decay); + log_info("inh_init = %11.4k\n", parameters->inh.init); + log_info("gsyn_excitatory_initial_value = %11.4k\n", + parameters->exc.synaptic_input_value); + log_info("gsyn_excitatory2_initial_value = %11.4k\n", + parameters->exc2.synaptic_input_value); + log_info("gsyn_inhibitory_initial_value = %11.4k\n", + parameters->inh.synaptic_input_value); +} + +#endif // _SYNAPSE_TYPES_DUAL_EXCITATORY_EXPONENTIAL_IMPL_H_ diff --git a/neural_modelling/src/meanfield_fixing/synapse_types/synapse_types_exponential_impl.h b/neural_modelling/src/meanfield_fixing/synapse_types/synapse_types_exponential_impl.h new file mode 100644 index 00000000000..6b6f557f09b --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/synapse_types/synapse_types_exponential_impl.h @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/*! + * \file + * \brief implementation of synapse_types.h for Exponential shaping + * + * \details This is used to give a simple exponential decay to synapses. + * + * If we have combined excitatory/inhibitory synapses it will be + * because both excitatory and inhibitory synaptic time-constants + * (and thus propagations) are identical. + */ + +#ifndef _SYNAPSE_TYPES_EXPONENTIAL_IMPL_H_ +#define _SYNAPSE_TYPES_EXPONENTIAL_IMPL_H_ + +//--------------------------------------- +// Macros +//--------------------------------------- +//! \brief Number of bits to encode the synapse type +//! \details ceil(log2(#SYNAPSE_TYPE_COUNT)) +#define SYNAPSE_TYPE_BITS 1 +//! \brief Number of synapse types +//! \details #NUM_EXCITATORY_RECEPTORS + #NUM_INHIBITORY_RECEPTORS +#define SYNAPSE_TYPE_COUNT 2 + +//! Number of excitatory receptors +#define NUM_EXCITATORY_RECEPTORS 1 +//! Number of inhibitory receptors +#define NUM_INHIBITORY_RECEPTORS 1 + +#include +#include +#include "synapse_types.h" + +//--------------------------------------- +// Synapse parameters +//--------------------------------------- +typedef struct exp_params_t { + decay_t decay; //!< Decay multiplier per timestep + decay_t init; //!< Initial decay factor + input_t synaptic_input_value; //!< The actual synaptic contribution +} exp_params_t; + +struct synapse_param_t { + exp_params_t exc; //!< Excitatory synaptic input + exp_params_t inh; //!< Inhibitory synaptic input +}; + +//! The supported synapse type indices +typedef enum { + EXCITATORY, //!< Excitatory synaptic input + INHIBITORY, //!< Inhibitory synaptic input +} exponential_synapse_input_buffer_regions; + +//--------------------------------------- +// Synapse shaping inline implementation +//--------------------------------------- + +//! \brief Shapes a single parameter +//! \param[in,out] exp_param: The parameter to shape +static inline void exp_shaping(exp_params_t *exp_param) { + // decay value according to decay constant + exp_param->synaptic_input_value = + decay_s1615(exp_param->synaptic_input_value, exp_param->decay); +} + +//! \brief decays the stuff thats sitting in the input buffers as these have not +//! yet been processed and applied to the neuron. +//! +//! This is to compensate for the valve behaviour of a synapse in biology +//! (spike goes in, synapse opens, then closes slowly) +//! plus the leaky aspect of a neuron. +//! +//! \param[in,out] parameters: the parameters to update +static inline void synapse_types_shape_input( + synapse_param_t *parameters) { + exp_shaping(¶meters->exc); + exp_shaping(¶meters->inh); +} + +//! \brief helper function to add input for a given timer period to a given +//! neuron +//! \param[in,out] exp_param: the pointer to the parameters to use +//! \param[in] input: the inputs to add. +static inline void add_input_exp(exp_params_t *exp_param, input_t input) { + exp_param->synaptic_input_value = exp_param->synaptic_input_value + + decay_s1615(input, exp_param->init); +} + +//! \brief adds the inputs for a give timer period to a given neuron that is +//! being simulated by this model +//! \param[in] synapse_type_index the type of input that this input is to be +//! considered (aka excitatory or inhibitory etc) +//! \param[in,out] parameters: the parameters to update +//! \param[in] input the inputs for that given synapse_type. +static inline void synapse_types_add_neuron_input( + index_t synapse_type_index, synapse_param_t *parameters, + input_t input) { + switch (synapse_type_index) { + case EXCITATORY: + add_input_exp(¶meters->exc, input); + break; + case INHIBITORY: + add_input_exp(¶meters->inh, input); + break; + } +} + +//! \brief extracts the excitatory input buffers from the buffers available +//! for a given parameter set +//! \param[in] parameters: the pointer to the parameters to use +//! \return the excitatory input buffers for a given neuron ID. +static inline input_t* synapse_types_get_excitatory_input( + input_t *excitatory_response, synapse_param_t *parameters) { + excitatory_response[0] = parameters->exc.synaptic_input_value; + return &excitatory_response[0]; +} + +//! \brief extracts the inhibitory input buffers from the buffers available +//! for a given parameter set +//! \param[in] parameters: the pointer to the parameters to use +//! \return the inhibitory input buffers for a given neuron ID. +static inline input_t* synapse_types_get_inhibitory_input( + input_t *inhibitory_response, synapse_param_t *parameters) { + inhibitory_response[0] = parameters->inh.synaptic_input_value; + return &inhibitory_response[0]; +} + +//! \brief returns a human readable character for the type of synapse. +//! examples would be X = excitatory types, I = inhibitory types etc etc. +//! \param[in] synapse_type_index: the synapse type index +//! (there is a specific index interpretation in each synapse type) +//! \return a human readable character representing the synapse type. +static inline const char *synapse_types_get_type_char( + index_t synapse_type_index) { + switch (synapse_type_index) { + case EXCITATORY: + return "X"; + case INHIBITORY: + return "I"; + default: + log_debug("did not recognise synapse type %i", synapse_type_index); + return "?"; + } +} + +//! \brief prints the input for a neuron ID given the available inputs +//! currently only executed when the models are in debug mode, as the prints +//! are controlled from the synapses.c print_inputs() method. +//! \param[in] parameters: the pointer to the parameters to use +static inline void synapse_types_print_input( + synapse_param_t *parameters) { + io_printf(IO_BUF, "%12.6k - %12.6k", + parameters->exc.synaptic_input_value, + parameters->inh.synaptic_input_value); +} + +//! \brief printer call +//! \param[in] parameters: the pointer to the parameters to print +static inline void synapse_types_print_parameters( + synapse_param_t *parameters) { + log_debug("exc_decay = %R\n", parameters->exc.decay); + log_debug("exc_init = %R\n", parameters->exc.init); + log_debug("inh_decay = %R\n", parameters->inh.decay); + log_debug("inh_init = %R\n", parameters->inh.init); + log_debug("gsyn_excitatory_initial_value = %11.4k\n", + parameters->exc.synaptic_input_value); + log_debug("gsyn_inhibitory_initial_value = %11.4k\n", + parameters->inh.synaptic_input_value); +} + +#endif // _SYNAPSE_TYPES_EXPONENTIAL_IMPL_H_ diff --git a/neural_modelling/src/meanfield_fixing/synapse_types/synapse_types_my_impl.h b/neural_modelling/src/meanfield_fixing/synapse_types/synapse_types_my_impl.h new file mode 100644 index 00000000000..525d8571d50 --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/synapse_types/synapse_types_my_impl.h @@ -0,0 +1,161 @@ +/*! \file + * \brief implementation of synapse_types.h for Exponential shaping +* +* \details This is used to give a simple exponential decay to synapses. +* +* If we have combined excitatory/inhibitory synapses it will be +* because both excitatory and inhibitory synaptic time-constants +* (and thus propogators) are identical. +*/ + + +#ifndef _SYNAPSE_TYPES_MY_IMPL_H_ +#define _SYNAPSE_TYPES_MY_IMPL_H_ + +// This is currently used for decaying the neuron input +#include + +#include + +// TODO: Determine the number of bits required by the synapse type in the +// synapse row data structure (i.e. enough bits to represent all desired +// synapse types) +// e.g. 1 bit for 2 possible types such as excitatory and inhibitory +// This must match the number returned by the python method +// get_n_synapse_type_bits +#define SYNAPSE_TYPE_BITS 1 + +// TODO: Determine the number of synapse types required +// (e.g. 2 for excitatory and inhibitory)] +// This must match the number returned by the python method +// get_n_synapse_types +#define SYNAPSE_TYPE_COUNT 2 + +// TODO: Define the parameters required to compute the synapse shape +// The number of parameters here should match the number per neuron +// written by the python method write_synapse_parameters +typedef struct synapse_param_t { + REAL my_exc_decay; + REAL my_exc_init; + REAL my_inh_decay; + REAL my_inh_init; + input_t my_input_buffer_excitatory_value; + input_t my_input_buffer_inhibitory_value; +} synapse_param_t; + +// Define receptor split +#define NUM_EXCITATORY_RECEPTORS 1 +#define NUM_INHIBITORY_RECEPTORS 1 + +// Include this here after defining the above items +#include + +// This makes it easy to keep track of which is which +typedef enum input_buffer_regions { + EXCITATORY, INHIBITORY, +} input_buffer_regions; + +//! \brief Shapes the values input into the neurons +//! \param[in] pointer to parameters the synapse parameter pointer passed in +//! \return Nothing +static inline void synapse_types_shape_input( + synapse_param_t *parameters) { + + parameters->my_input_buffer_excitatory_value = decay_s1615( + parameters->my_input_buffer_excitatory_value, + parameters->my_exc_decay); + parameters->my_input_buffer_inhibitory_value = decay_s1615( + parameters->my_input_buffer_inhibitory_value, + parameters->my_inh_decay); +} + + +//! \brief Adds the initial value to an input buffer for this shaping. Allows +// the input to be scaled before being added. +//! \param[in-out] input_buffers the pointer to the input buffers +//! \param[in] synapse_type_index the index of the synapse type to add the +// value to +//! \param[in] pointer to parameters the synapse parameters passed in +//! \param[in] input the input to be added +//! \return None +static inline void synapse_types_add_neuron_input( + index_t synapse_type_index, synapse_param_t *parameters, + input_t input) { + if (synapse_type_index == EXCITATORY) { + parameters->my_input_buffer_excitatory_value = + parameters->my_input_buffer_excitatory_value + + decay_s1615(input, parameters->my_exc_init); + + } else if (synapse_type_index == INHIBITORY) { + parameters->my_input_buffer_inhibitory_value = + parameters->my_input_buffer_inhibitory_value + + decay_s1615(input, parameters->my_inh_init); + } +} + +//! \brief Gets the excitatory input for a given neuron +//! \param[in] pointer to parameters the synapse parameters passed in +//! \return the first entry in the array of excitatory input values +static inline input_t* synapse_types_get_excitatory_input( + input_t *excitatory_response, synapse_param_t *parameters) { + excitatory_response[0] = parameters->my_input_buffer_excitatory_value; + return &excitatory_response[0]; +} + +//! \brief Gets the inhibitory input for a given neuron +//! \param[in] pointer to parameters the synapse parameters passed in +//! \return the first entry in array of inhibitory input values +static inline input_t* synapse_types_get_inhibitory_input( + input_t *inhibitory_response, synapse_param_t *parameters) { + inhibitory_response[0] = parameters->my_input_buffer_inhibitory_value; + return &inhibitory_response[0]; +} + +//! \brief returns a human readable character for the type of synapse, for +// debug purposes +//! examples would be X = excitatory types, I = inhibitory types etc etc. +//! \param[in] synapse_type_index the synapse type index +//! \return a human readable character representing the synapse type. +static inline const char *synapse_types_get_type_char( + index_t synapse_type_index) { + + // TODO: Update with your synapse types + if (synapse_type_index == EXCITATORY) { + return "X"; + } else if (synapse_type_index == INHIBITORY) { + return "I"; + } else { + log_debug("Did not recognise synapse type %i", synapse_type_index); + return "?"; + } +} + +//! \brief prints the input for a neuron ID for debug purposes +//! \param[in] pointer to parameters the synapse parameters passed in +//! \return Nothing +static inline void synapse_types_print_input( + synapse_param_t *parameters) { + io_printf(IO_BUF, "%12.6k - %12.6k", + parameters->my_input_buffer_excitatory_value, + parameters->my_input_buffer_inhibitory_value); + // TODO: Does this function need the remaining parameters adding to it? +} + +//! \brief print parameters call +//! \param[in] parameter: the pointer to the parameters to print +//! \return Nothing +static inline void synapse_types_print_parameters( + synapse_param_t *parameters) { + + // TODO: Update to print your parameters + log_info("my_exc_decay = %R\n", (unsigned fract) parameters->my_exc_decay); + log_info("my_exc_init = %R\n", (unsigned fract) parameters->my_exc_init); + log_info("my_inh_decay = %R\n", (unsigned fract) parameters->my_inh_decay); + log_info("my_inh_init = %R\n", (unsigned fract) parameters->my_inh_init); + log_info("my_excitatory_initial_value = %11.4k\n", + parameters->my_input_buffer_excitatory_value); + log_info("my_inhibitory_initial_value = %11.4k\n", + parameters->my_input_buffer_inhibitory_value); +} + +#endif // _SYNAPSE_TYPES_MY_IMPL_H_ diff --git a/neural_modelling/src/meanfield_fixing/synapse_types/synapse_types_semd_impl.h b/neural_modelling/src/meanfield_fixing/synapse_types/synapse_types_semd_impl.h new file mode 100644 index 00000000000..1360aab1445 --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/synapse_types/synapse_types_semd_impl.h @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/*! \file +* +* \brief implementation of synapse_types.h for sEMD synapses. +* +* \details To be filled in... +*/ + +#ifndef _SYNAPSE_TYPES_SEMD_IMPL_H_ +#define _SYNAPSE_TYPES_SEMD_IMPL_H_ + +//--------------------------------------- +// Macros +//--------------------------------------- +//! \brief Number of bits to encode the synapse type +//! \details ceil(log2(#SYNAPSE_TYPE_COUNT)) +#define SYNAPSE_TYPE_BITS 2 +//! \brief Number of synapse types +//! \details #NUM_EXCITATORY_RECEPTORS + #NUM_INHIBITORY_RECEPTORS +#define SYNAPSE_TYPE_COUNT 3 + +//! Number of excitatory receptors +#define NUM_EXCITATORY_RECEPTORS 2 +//! Number of inhibitory receptors +#define NUM_INHIBITORY_RECEPTORS 1 + +#include +#include +#include "synapse_types.h" + +//--------------------------------------- +// Synapse parameters +//--------------------------------------- +typedef struct exp_params_t { + decay_t decay; //!< Decay multiplier per timestep + decay_t init; //!< Initial decay factor + input_t synaptic_input_value; //!< The actual synaptic contribution +} exp_params_t; + +struct synapse_param_t { + exp_params_t exc; //!< First excitatory synaptic input + exp_params_t exc2; //!< Second excitatory synaptic input + exp_params_t inh; //!< Inhibitory synaptic input + //! Output scaling factor derived from first excitatory input + input_t multiplicator; + //! History storage used to reset synaptic state + input_t exc2_old; + //! Scaling factor for the secondary response + input_t scaling_factor; +}; + +//! The supported synapse type indices +typedef enum { + EXCITATORY_ONE, //!< First excitatory synaptic input + EXCITATORY_TWO, //!< Second excitatory synaptic input + INHIBITORY, //!< Inhibitory synaptic input +} synapse_semd_input_buffer_regions; + +//--------------------------------------- +// Synapse shaping inline implementation +//--------------------------------------- + +//! \brief Shapes a single parameter +//! \param[in,out] exp_param: The parameter to shape +static inline void exp_shaping(exp_params_t *exp_param) { + // decay value according to decay constant + exp_param->synaptic_input_value = + decay_s1615(exp_param->synaptic_input_value, exp_param->decay); +} + +//! \brief decays the stuff thats sitting in the input buffers as these have not +//! yet been processed and applied to the neuron. +//! +//! This is to compensate for the valve behaviour of a synapse in biology +//! (spike goes in, synapse opens, then closes slowly) +//! plus the leaky aspect of a neuron. +//! +//! \param[in,out] parameters: the pointer to the parameters to use +static inline void synapse_types_shape_input(synapse_param_t *parameters) { + exp_shaping(¶meters->exc); + exp_shaping(¶meters->exc2); + exp_shaping(¶meters->inh); +} + +//! \brief helper function to add input for a given timer period to a given +//! neuron +//! \param[in,out] parameter: the parameter to update +//! \param[in] input: the input to add. +static inline void add_input_exp(exp_params_t *parameter, input_t input) { + parameter->synaptic_input_value = parameter->synaptic_input_value + + decay_s1615(input, parameter->init); +} + +//! \brief adds the inputs for a give timer period to a given neuron that is +//! being simulated by this model +//! \param[in] synapse_type_index: the type of input that this input is to be +//! considered (aka excitatory or inhibitory etc) +//! \param[in,out] parameter: the pointer to the parameters to use +//! \param[in] input: the input for that given synapse_type. +static inline void synapse_types_add_neuron_input( + index_t synapse_type_index, synapse_param_t *parameter, + input_t input) { + switch (synapse_type_index) { + case EXCITATORY_ONE: + add_input_exp(¶meter->exc, input); + break; + case EXCITATORY_TWO: + add_input_exp(¶meter->exc2, input); + break; + case INHIBITORY: + add_input_exp(¶meter->inh, input); + break; + } +} + +//! \brief extracts the excitatory input buffers from the buffers available +//! for a given parameter set +//! \param[in] parameters: the pointer to the parameters to use +//! \return the excitatory input buffers for a given neuron ID. +static inline input_t *synapse_types_get_excitatory_input( + input_t *excitatory_response, synapse_param_t *parameters) { + if (parameters->exc2.synaptic_input_value >= 0.001 + && parameters->multiplicator == 0 + && parameters->exc2_old == 0) { + parameters->multiplicator = parameters->exc.synaptic_input_value; + } else if (parameters->exc2.synaptic_input_value < 0.001) { + parameters->multiplicator = 0; + } + + parameters->exc2_old = parameters->exc2.synaptic_input_value; + + excitatory_response[0] = 0; + excitatory_response[1] = + parameters->exc2.synaptic_input_value * parameters->multiplicator + * parameters->scaling_factor; + return &excitatory_response[0]; +} + +//! \brief extracts the inhibitory input buffers from the buffers available +//! for a given parameter set +//! \param[in] parameters: the pointer to the parameters to use +//! \return the inhibitory input buffers for a given neuron ID. +static inline input_t *synapse_types_get_inhibitory_input( + input_t *inhibitory_response, synapse_param_t *parameters) { + inhibitory_response[0] = parameters->inh.synaptic_input_value; + return &inhibitory_response[0]; +} + +//! \brief returns a human readable character for the type of synapse. +//! examples would be X = excitatory types, I = inhibitory types etc etc. +//! \param[in] synapse_type_index: the synapse type index +//! (there is a specific index interpretation in each synapse type) +//! \return a human readable character representing the synapse type. +static inline const char *synapse_types_get_type_char( + index_t synapse_type_index) { + switch (synapse_type_index) { + case EXCITATORY_ONE: + return "X1"; + case EXCITATORY_TWO: + return "X2"; + case INHIBITORY: + return "I"; + default: + log_debug("did not recognise synapse type %i", synapse_type_index); + return "?"; + } +} + +//! \brief prints the input for a neuron ID given the available inputs +//! currently only executed when the models are in debug mode, as the prints +//! are controlled from the synapses.c print_inputs() method. +//! \param[in] parameters: the parameters to print +static inline void synapse_types_print_input(synapse_param_t *parameters) { + io_printf(IO_BUF, "%12.6k + %12.6k - %12.6k", + parameters->exc.synaptic_input_value, + parameters->exc2.synaptic_input_value, + parameters->inh.synaptic_input_value); +} + +//! \brief printer call +//! \param[in] parameters: the pointer to the parameters to print +static inline void synapse_types_print_parameters(synapse_param_t *parameters) { + log_info("exc_decay = %11.4k\n", parameters->exc.decay); + log_info("exc_init = %11.4k\n", parameters->exc.init); + log_info("exc2_decay = %11.4k\n", parameters->exc2.decay); + log_info("exc2_init = %11.4k\n", parameters->exc2.init); + log_info("inh_decay = %11.4k\n", parameters->inh.decay); + log_info("inh_init = %11.4k\n", parameters->inh.init); + log_info("gsyn_excitatory_initial_value = %11.4k\n", + parameters->exc.synaptic_input_value); + log_info("gsyn_excitatory2_initial_value = %11.4k\n", + parameters->exc2.synaptic_input_value); + log_info("gsyn_inhibitory_initial_value = %11.4k\n", + parameters->inh.synaptic_input_value); + log_info("multiplicator = %11.4k\n", parameters->multiplicator); + log_info("exc2_old = %11.4k\n", parameters->exc2_old); + log_info("scaling_factor = %11.4k\n", parameters->scaling_factor); +} + +#endif // _SYNAPSE_TYPES_SEMD_IMPL_H_ diff --git a/neural_modelling/src/meanfield_fixing/synapses.c b/neural_modelling/src/meanfield_fixing/synapses.c new file mode 100644 index 00000000000..2a384fe6384 --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/synapses.c @@ -0,0 +1,400 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Implementation of non-inlined API in synapses.h +#include "synapses.h" +#include "spike_processing.h" +#include "meanfield.h" +#include "plasticity/synapse_dynamics.h" +#include +#include +#include +#include + +//! if using profiler import profiler tags +#ifdef PROFILER_ENABLED +#include "profile_tags.h" +#endif //PROFILER_ENABLED + +//! Globals required for synapse benchmarking to work. +uint32_t num_fixed_pre_synaptic_events = 0; + +//! The number of neurons +static uint32_t n_neurons; + +//! The number of synapse types +static uint32_t n_synapse_types; + +//! Ring buffers to handle delays between synapses and neurons +static weight_t *ring_buffers; + +//! Ring buffer size +static uint32_t ring_buffer_size; + +//! Amount to left shift the ring buffer by to make it an input +static uint32_t *ring_buffer_to_input_left_shifts; + +//! \brief Number of bits needed for the synapse type and index +//! \details +//! ``` +//! synapse_index_bits + synapse_type_bits +//! ``` +static uint32_t synapse_type_index_bits; +//! \brief Mask to pick out the synapse type and index. +//! \details +//! ``` +//! synapse_index_mask | synapse_type_mask +//! ``` +static uint32_t synapse_type_index_mask; +//! Number of bits in the synapse index +static uint32_t synapse_index_bits; +//! Mask to pick out the synapse index. +static uint32_t synapse_index_mask; +//! Number of bits in the synapse type +static uint32_t synapse_type_bits; +//! Mask to pick out the synapse type. +static uint32_t synapse_type_mask; + +//! Count of the number of times the ring buffers have saturated +uint32_t synapses_saturation_count = 0; + + +/* PRIVATE FUNCTIONS */ + +#if LOG_LEVEL >= LOG_DEBUG +//! \brief get the synapse type character +//! \param[in] synapse_type: the synapse type +//! \return a single character string describing the synapse type +static inline const char *get_type_char(uint32_t synapse_type) { + return neuron_get_synapse_type_char(synapse_type); +} +#endif // LOG_LEVEL >= LOG_DEBUG + +//! \brief Print a synaptic row. +//! +//! Only does anything when debugging. +//! \param[in] synaptic_row: The synaptic row to print +static inline void print_synaptic_row(synaptic_row_t synaptic_row) { + log_debug("Synaptic row, at address %08x, Num plastic words:%u", + (uint32_t) synaptic_row, synapse_row_plastic_size(synaptic_row)); + if (synaptic_row == NULL) { + return; + } +#if LOG_LEVEL >= LOG_DEBUG + io_printf(IO_BUF, "----------------------------------------\n"); + + // Get details of fixed region + synapse_row_fixed_part_t *fixed_region = + synapse_row_fixed_region(synaptic_row); + address_t fixed_synapses = synapse_row_fixed_weight_controls(fixed_region); + size_t n_fixed_synapses = synapse_row_num_fixed_synapses(fixed_region); + io_printf(IO_BUF, + "Fixed region %u fixed synapses (%u plastic control words):\n", + n_fixed_synapses, synapse_row_num_plastic_controls(fixed_region)); + + for (uint32_t i = 0; i < n_fixed_synapses; i++) { + uint32_t synapse = fixed_synapses[i]; + uint32_t synapse_type = synapse_row_sparse_type( + synapse, synapse_index_bits, synapse_type_mask); + + io_printf(IO_BUF, "%08x [%3d: (w: %5u (=", + synapse, i, synapse_row_sparse_weight(synapse)); + synapses_print_weight(synapse_row_sparse_weight(synapse), + ring_buffer_to_input_left_shifts[synapse_type]); + io_printf(IO_BUF, "nA) d: %2u, %s, n = %3u)] - {%08x %08x}\n", + synapse_row_sparse_delay(synapse, synapse_type_index_bits), + get_type_char(synapse_type), + synapse_row_sparse_index(synapse, synapse_index_mask), + SYNAPSE_DELAY_MASK, synapse_type_index_bits); + } + + // If there's a plastic region + if (synapse_row_plastic_size(synaptic_row) > 0) { + io_printf(IO_BUF, "----------------------------------------\n"); + synapse_row_plastic_data_t *plastic_data = + synapse_row_plastic_region(synaptic_row); + synapse_dynamics_print_plastic_synapses( + plastic_data, fixed_region, ring_buffer_to_input_left_shifts); + } + + io_printf(IO_BUF, "----------------------------------------\n"); +#endif // LOG_LEVEL >= LOG_DEBUG +} + +//! \brief Print the contents of the ring buffers. +//! \details Only does anything when debugging. +//! \param[in] time: The current timestamp +static inline void print_ring_buffers(uint32_t time) { + log_debug("Ring Buffer at %u", time); +#if LOG_LEVEL >= LOG_DEBUG + io_printf(IO_BUF, "----------------------------------------\n"); + for (uint32_t n = 0; n < n_neurons; n++) { + for (uint32_t t = 0; t < n_synapse_types; t++) { + // Determine if this row can be omitted + for (uint32_t d = 0; d < (1 << SYNAPSE_DELAY_BITS); d++) { + if (ring_buffers[synapses_get_ring_buffer_index( + d + time, t, n, synapse_type_index_bits, + synapse_index_bits)] != 0) { + goto doPrint; + } + } + continue; + doPrint: + // Have to print the row + io_printf(IO_BUF, "%3d(%s):", n, get_type_char(t)); + for (uint32_t d = 0; d < (1 << SYNAPSE_DELAY_BITS); d++) { + io_printf(IO_BUF, " "); + uint32_t ring_buffer_index = synapses_get_ring_buffer_index( + d + time, t, n, synapse_type_index_bits, + synapse_index_bits); + synapses_print_weight(ring_buffers[ring_buffer_index], + ring_buffer_to_input_left_shifts[t]); + } + io_printf(IO_BUF, "\n"); + } + } + io_printf(IO_BUF, "----------------------------------------\n"); +#endif // LOG_LEVEL >= LOG_DEBUG +} + +//! \brief Print the neuron inputs. +//! \details Only does anything when debugging. +static inline void print_inputs(void) { +#if LOG_LEVEL >= LOG_DEBUG + log_debug("Inputs"); + neuron_print_inputs(); +#endif // LOG_LEVEL >= LOG_DEBUG +} + + +//! \brief The "inner loop" of the neural simulation. +//! \details Every spike event could cause up to 256 different weights to +//! be put into the ring buffer. +//! \param[in] fixed_region: The fixed region of the synaptic matrix +//! \param[in] time: The current simulation time +static inline void process_fixed_synapses( + synapse_row_fixed_part_t *fixed_region, uint32_t time) { + uint32_t *synaptic_words = synapse_row_fixed_weight_controls(fixed_region); + uint32_t fixed_synapse = synapse_row_num_fixed_synapses(fixed_region); + + num_fixed_pre_synaptic_events += fixed_synapse; + + for (; fixed_synapse > 0; fixed_synapse--) { + // Get the next 32 bit word from the synaptic_row + // (should auto increment pointer in single instruction) + uint32_t synaptic_word = *synaptic_words++; + + // Extract components from this word + uint32_t delay = + synapse_row_sparse_delay(synaptic_word, synapse_type_index_bits); + uint32_t combined_synapse_neuron_index = synapse_row_sparse_type_index( + synaptic_word, synapse_type_index_mask); + uint32_t weight = synapse_row_sparse_weight(synaptic_word); + + // Convert into ring buffer offset + uint32_t ring_buffer_index = synapses_get_ring_buffer_index_combined( + delay + time, combined_synapse_neuron_index, + synapse_type_index_bits); + + // Add weight to current ring buffer value + uint32_t accumulation = ring_buffers[ring_buffer_index] + weight; + + // If 17th bit is set, saturate accumulator at UINT16_MAX (0xFFFF) + // **NOTE** 0x10000 can be expressed as an ARM literal, + // but 0xFFFF cannot. Therefore, we use (0x10000 - 1) + // to obtain this value + uint32_t sat_test = accumulation & 0x10000; + if (sat_test) { + accumulation = sat_test - 1; + synapses_saturation_count++; + } + + // Store saturated value back in ring-buffer + ring_buffers[ring_buffer_index] = accumulation; + } +} + +//! Print output debug data on the synapses +static inline void print_synapse_parameters(void) { +// only if the models are compiled in debug mode will this method contain +// said lines. +#if LOG_LEVEL >= LOG_DEBUG + // again neuron_synapse_shaping_params has moved to implementation + neuron_print_synapse_parameters(); +#endif // LOG_LEVEL >= LOG_DEBUG +} + +/* INTERFACE FUNCTIONS */ +bool synapses_initialise( + address_t synapse_params_address, uint32_t n_neurons_value, + uint32_t n_synapse_types_value, + uint32_t **ring_buffer_to_input_buffer_left_shifts, + bool* clear_input_buffers_of_late_packets_init) { + log_debug("synapses_initialise: starting"); + n_neurons = n_neurons_value; + n_synapse_types = n_synapse_types_value; + + // Set up ring buffer left shifts + ring_buffer_to_input_left_shifts = + spin1_malloc(n_synapse_types * sizeof(uint32_t)); + if (ring_buffer_to_input_left_shifts == NULL) { + log_error("Not enough memory to allocate ring buffer"); + return false; + } + + // read bool flag about dropping packets that arrive too late + *clear_input_buffers_of_late_packets_init = synapse_params_address[0]; + + // shift read by 1 word. + synapse_params_address += 1; + + // read in ring buffer to input left shifts + spin1_memcpy( + ring_buffer_to_input_left_shifts, synapse_params_address, + n_synapse_types * sizeof(uint32_t)); + *ring_buffer_to_input_buffer_left_shifts = + ring_buffer_to_input_left_shifts; + + log_debug("synapses_initialise: completed successfully"); + print_synapse_parameters(); + + uint32_t n_neurons_power_2 = n_neurons; + uint32_t log_n_neurons = 1; + if (n_neurons != 1) { + if (!is_power_of_2(n_neurons)) { + n_neurons_power_2 = next_power_of_2(n_neurons); + } + log_n_neurons = ilog_2(n_neurons_power_2); + } + + uint32_t n_synapse_types_power_2 = n_synapse_types; + if (!is_power_of_2(n_synapse_types)) { + n_synapse_types_power_2 = next_power_of_2(n_synapse_types); + } + uint32_t log_n_synapse_types = ilog_2(n_synapse_types_power_2); + + uint32_t n_ring_buffer_bits = + log_n_neurons + log_n_synapse_types + SYNAPSE_DELAY_BITS; + ring_buffer_size = 1 << (n_ring_buffer_bits); + + ring_buffers = spin1_malloc(ring_buffer_size * sizeof(weight_t)); + if (ring_buffers == NULL) { + log_error("Could not allocate %u entries for ring buffers", + ring_buffer_size); + } + for (uint32_t i = 0; i < ring_buffer_size; i++) { + ring_buffers[i] = 0; + } + + synapse_type_index_bits = log_n_neurons + log_n_synapse_types; + synapse_type_index_mask = (1 << synapse_type_index_bits) - 1; + synapse_index_bits = log_n_neurons; + synapse_index_mask = (1 << synapse_index_bits) - 1; + synapse_type_bits = log_n_synapse_types; + synapse_type_mask = (1 << log_n_synapse_types) - 1; + return true; +} + +void synapses_do_timestep_update(timer_t time) { + print_ring_buffers(time); + + // Transfer the input from the ring buffers into the input buffers + for (uint32_t neuron_index = 0; neuron_index < n_neurons; + neuron_index++) { + // Loop through all synapse types + for (uint32_t synapse_type_index = 0; + synapse_type_index < n_synapse_types; synapse_type_index++) { + // Get index in the ring buffers for the current time slot for + // this synapse type and neuron + uint32_t ring_buffer_index = synapses_get_ring_buffer_index( + time, synapse_type_index, neuron_index, + synapse_type_index_bits, synapse_index_bits); + + // Convert ring-buffer entry to input and add on to correct + // input for this synapse type and neuron + neuron_add_inputs( + synapse_type_index, neuron_index, + synapses_convert_weight_to_input( + ring_buffers[ring_buffer_index], + ring_buffer_to_input_left_shifts[synapse_type_index])); + + // Clear ring buffer + ring_buffers[ring_buffer_index] = 0; + } + } + + print_inputs(); +} + +bool synapses_process_synaptic_row( + uint32_t time, synaptic_row_t row, bool *write_back) { + + // Get address of non-plastic region from row + synapse_row_fixed_part_t *fixed_region = synapse_row_fixed_region(row); + + // **TODO** multiple optimised synaptic row formats + //if (plastic_tag(row) == 0) { + // If this row has a plastic region + if (synapse_row_plastic_size(row) > 0) { + // Get region's address + synapse_row_plastic_data_t *plastic_data = + synapse_row_plastic_region(row); + + // Process any plastic synapses + profiler_write_entry_disable_fiq( + PROFILER_ENTER | PROFILER_PROCESS_PLASTIC_SYNAPSES); + if (!synapse_dynamics_process_plastic_synapses(plastic_data, + fixed_region, ring_buffers, time)) { + return false; + } + profiler_write_entry_disable_fiq( + PROFILER_EXIT | PROFILER_PROCESS_PLASTIC_SYNAPSES); + + // Perform DMA write back + *write_back = true; + } + + // Process any fixed synapses + // **NOTE** this is done after initiating DMA in an attempt + // to hide cost of DMA behind this loop to improve the chance + // that the DMA controller is ready to read next synaptic row afterwards + process_fixed_synapses(fixed_region, time); + //} + return true; +} + +uint32_t synapses_get_pre_synaptic_events(void) { + return (num_fixed_pre_synaptic_events + + synapse_dynamics_get_plastic_pre_synaptic_events()); +} + +void synapses_flush_ring_buffers(void) { + for (uint32_t i = 0; i < ring_buffer_size; i++) { + ring_buffers[i] = 0; + } +} + +//! \brief Clear DTCM used by synapses +//! \return true if successful +bool synapses_shut_down(void) { + sark_free(ring_buffer_to_input_left_shifts); + sark_free(ring_buffers); + num_fixed_pre_synaptic_events = 0; + synapses_saturation_count = 0; + return true; +} diff --git a/neural_modelling/src/meanfield_fixing/synapses.h b/neural_modelling/src/meanfield_fixing/synapses.h new file mode 100644 index 00000000000..2cfcabfad8e --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/synapses.h @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Operations on synapses +#ifndef _SYNAPSES_H_ +#define _SYNAPSES_H_ + +#include +#include "synapse_row.h" +#include "meanfield.h" + +//! Count of the number of times the synapses have saturated their weights. +extern uint32_t synapses_saturation_count; + + +//! \brief Get the index of the ring buffer for a given timestep, synapse type +//! and neuron index +//! \param[in] simulation_timestep: +//! \param[in] synapse_type_index: +//! \param[in] neuron_index: +//! \param[in] synapse_type_index_bits: +//! \param[in] synapse_index_bits: +//! \return Index into the ring buffer +static inline index_t synapses_get_ring_buffer_index( + uint32_t simulation_timestep, uint32_t synapse_type_index, + uint32_t neuron_index, uint32_t synapse_type_index_bits, + uint32_t synapse_index_bits) { + return ((simulation_timestep & SYNAPSE_DELAY_MASK) << synapse_type_index_bits) + | (synapse_type_index << synapse_index_bits) + | neuron_index; +} + +//! \brief Get the index of the ring buffer for a given timestep and combined +//! synapse type and neuron index (as stored in a synapse row) +//! \param[in] simulation_timestep: +//! \param[in] combined_synapse_neuron_index: +//! \param[in] synapse_type_index_bits: +//! \return Index into the ring buffer +static inline index_t synapses_get_ring_buffer_index_combined( + uint32_t simulation_timestep, + uint32_t combined_synapse_neuron_index, + uint32_t synapse_type_index_bits) { + return ((simulation_timestep & SYNAPSE_DELAY_MASK) << synapse_type_index_bits) + | combined_synapse_neuron_index; +} + +//! \brief Converts a weight stored in a synapse row to an input +//! \param[in] weight: the weight to convert in synapse-row form +//! \param[in] left_shift: the shift to use when decoding +//! \return the actual input weight for the model +static inline input_t synapses_convert_weight_to_input( + weight_t weight, uint32_t left_shift) { + union { + int_k_t input_type; + s1615 output_type; + } converter; + + converter.input_type = (int_k_t) (weight) << left_shift; + + return converter.output_type; +} + +//! \brief Print the weight of a synapse +//! \param[in] weight: the weight to print in synapse-row form +//! \param[in] left_shift: the shift to use when decoding +static inline void synapses_print_weight( + weight_t weight, uint32_t left_shift) { + if (weight != 0) { + io_printf(IO_BUF, "%12.6k", + synapses_convert_weight_to_input(weight, left_shift)); + } else { + io_printf(IO_BUF, " "); + } +} + +//! \brief Initialise the synapse processing +//! \param[in] synapse_params_address: Synapse configuration in SDRAM +//! \param[in] n_neurons: Number of neurons to simulate +//! \param[in] n_synapse_types: Number of synapse types +//! \param[out] ring_buffer_to_input_buffer_left_shifts: +//! Array of shifts to use when converting from ring buffer values to input +//! buffer values +//! \return True if successfully initialised. False otherwise. +bool synapses_initialise( + address_t synapse_params_address, + uint32_t n_neurons, uint32_t n_synapse_types, + uint32_t **ring_buffer_to_input_buffer_left_shifts, + bool* clear_input_buffers_of_late_packets_init); + +//! \brief Do all the synapse processing for a timestep. +//! \param[in] time: the current simulation time +void synapses_do_timestep_update(timer_t time); + +//! \brief process a synaptic row +//! \param[in] time: the simulated time +//! \param[in] row: the synaptic row in question +//! \param[out] write_back: whether to write back to SDRAM +//! \return True if successful +bool synapses_process_synaptic_row( + uint32_t time, synaptic_row_t row, bool *write_back); + +//! \brief returns the counters for plastic and fixed pre synaptic events based +//! on (if the model was compiled with SYNAPSE_BENCHMARK parameter) or +//! returns 0 +//! \return the counter for plastic and fixed pre synaptic events or 0 +uint32_t synapses_get_pre_synaptic_events(void); + +//! \brief flush the ring buffers +void synapses_flush_ring_buffers(void); + +//! \brief allows clearing of DTCM used by synapses +//! \return true if successful, false otherwise +bool synapses_shut_down(void); + +#endif // _SYNAPSES_H_ diff --git a/neural_modelling/src/meanfield_fixing/threshold_types/my_threshold_type.h b/neural_modelling/src/meanfield_fixing/threshold_types/my_threshold_type.h new file mode 100644 index 00000000000..e56db3fdace --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/threshold_types/my_threshold_type.h @@ -0,0 +1,23 @@ +#ifndef _MY_THRESHOLD_TYPE_H_ +#define _MY_THRESHOLD_TYPE_H_ + +#include + +typedef struct threshold_type_t { + // TODO: Add any additional parameters here + REAL threshold_value; + REAL my_param; +} threshold_type_t; + +static inline bool threshold_type_is_above_threshold(state_t value, + threshold_type_t *threshold_type) { + + // TODO: Perform the appropriate operations + REAL test_value = value * threshold_type->my_param; + + // TODO: Update to return true or false depending on if the + // threshold has been reached + return REAL_COMPARE(test_value, >=, threshold_type->threshold_value); +} + +#endif // _MY_THRESHOLD_TYPE_H_ diff --git a/neural_modelling/src/meanfield_fixing/threshold_types/threshold_type.h b/neural_modelling/src/meanfield_fixing/threshold_types/threshold_type.h new file mode 100644 index 00000000000..6fa28a54633 --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/threshold_types/threshold_type.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \dir +//! \brief Neuron firing thresholds +//! \file +//! \brief API for threshold types + +#ifndef _THRESHOLD_TYPE_H_ +#define _THRESHOLD_TYPE_H_ + +#include + +// Forward declaration of the threshold pointer type +struct threshold_type_t; +typedef struct threshold_type_t threshold_type_t; +//! Pointer to a threshold type +typedef threshold_type_t* threshold_type_pointer_t; + +//! \brief Determines if the value given is above the threshold value +//! \param[in] value: The value to determine if it is above the threshold +//! \param[in] threshold_type: The parameters to use to determine the result +//! \return True if the neuron should fire +static bool threshold_type_is_above_threshold( + state_t value, threshold_type_t *threshold_type); + +#endif // _THRESHOLD_TYPE_H_ diff --git a/neural_modelling/src/meanfield_fixing/threshold_types/threshold_type_maass_stochastic.h b/neural_modelling/src/meanfield_fixing/threshold_types/threshold_type_maass_stochastic.h new file mode 100644 index 00000000000..936fa0e7cce --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/threshold_types/threshold_type_maass_stochastic.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Stochastic threshold, due to Wolfgang Maass _et al._ +#ifndef _THRESHOLD_TYPE_STOCHASTIC_H_ +#define _THRESHOLD_TYPE_STOCHASTIC_H_ + +#include "threshold_type.h" +#include +#include + +//! Probability of firing when at saturation +#define PROB_SATURATION 0.8k + +//! Stochastic threshold configuration +struct threshold_type_t { + //! sensitivity of soft threshold to membrane voltage [mV-1] + //! (inverted in python code) + REAL du_th_inv; + //! time constant for soft threshold [ms-1] + //! (inverted in python code) + REAL tau_th_inv; + //! soft threshold value [mV] + REAL v_thresh; + //! time step scaling factor + REAL neg_machine_time_step_ms_div_10; +}; + +//! \brief Determines if the value given is above the threshold value +//! \param[in] value: The value to determine if it is above the threshold +//! \param[in] threshold_type: The parameters to use to determine the result +//! \return True if the neuron should fire +static inline bool threshold_type_is_above_threshold( + state_t value, threshold_type_t *threshold_type) { + UREAL random_number = ukbits(mars_kiss64_simp() & 0xFFFF); + + REAL exponent = (value - threshold_type->v_thresh) + * threshold_type->du_th_inv; + + // if exponent is large, further calculation is unnecessary + // (result --> prob_saturation). + UREAL result; + if (exponent < 5.0k) { + REAL hazard = expk(exponent) * threshold_type->tau_th_inv; + result = (1. - expk(hazard * + threshold_type->neg_machine_time_step_ms_div_10)) * + PROB_SATURATION; + } else { + result = PROB_SATURATION; + } + + return REAL_COMPARE(result, >=, random_number); +} + +#endif // _THRESHOLD_TYPE_STOCHASTIC_H_ diff --git a/neural_modelling/src/meanfield_fixing/threshold_types/threshold_type_none.h b/neural_modelling/src/meanfield_fixing/threshold_types/threshold_type_none.h new file mode 100644 index 00000000000..e525603e052 --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/threshold_types/threshold_type_none.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Threshold that never fires +#ifndef _THRESHOLD_TYPE_NONE_H_ +#define _THRESHOLD_TYPE_NONE_H_ + +#include "threshold_type.h" + +struct threshold_type_t { +}; + +//! \brief Determines if the value given is above the threshold value +//! \param[in] value: The value to determine if it is above the threshold +//! \param[in] threshold_type: The parameters to use to determine the result +//! \return True if the neuron should fire +static inline bool threshold_type_is_above_threshold( + UNUSED state_t value, UNUSED threshold_type_t *threshold_type) { + return 0; +} + +#endif // _THRESHOLD_TYPE_NONE_H_ diff --git a/neural_modelling/src/meanfield_fixing/threshold_types/threshold_type_static.h b/neural_modelling/src/meanfield_fixing/threshold_types/threshold_type_static.h new file mode 100644 index 00000000000..30c9b238f93 --- /dev/null +++ b/neural_modelling/src/meanfield_fixing/threshold_types/threshold_type_static.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2017-2019 The University of Manchester + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//! \file +//! \brief Threshold that fires at a fixed level +#ifndef _THRESHOLD_TYPE_STATIC_H_ +#define _THRESHOLD_TYPE_STATIC_H_ + +#include "threshold_type.h" + +//! Static threshold configuration +struct threshold_type_t { + //! The value of the static threshold + REAL threshold_value; +}; + +//! \brief Determines if the value given is above the threshold value +//! \param[in] value: The value to determine if it is above the threshold +//! \param[in] threshold_type: The parameters to use to determine the result +//! \return True if the neuron should fire +static inline bool threshold_type_is_above_threshold( + state_t value, threshold_type_t *threshold_type) { + return REAL_COMPARE(value, >=, threshold_type->threshold_value); +} + +#endif // _THRESHOLD_TYPE_STATIC_H_ diff --git a/spynnaker/pyNN/models/neuron/__init__.py b/spynnaker/pyNN/models/neuron/__init__.py index 7b96f90ab8b..c4722420fa8 100644 --- a/spynnaker/pyNN/models/neuron/__init__.py +++ b/spynnaker/pyNN/models/neuron/__init__.py @@ -20,7 +20,10 @@ from .abstract_pynn_neuron_model import AbstractPyNNNeuronModel from .abstract_pynn_neuron_model_standard import ( AbstractPyNNNeuronModelStandard) +from .abstract_pynn_meanfield_model_standard import ( + AbstractPyNNMeanfieldModelStandard) __all__ = ["AbstractPopulationVertex", "AbstractPyNNNeuronModel", - "AbstractPyNNNeuronModelStandard", "ConnectionHolder", + "AbstractPyNNNeuronModelStandard", + "AbstractPyNNMeanfieldModelStandard", "ConnectionHolder", "PopulationMachineVertex", "SynapticManager"] diff --git a/spynnaker/pyNN/models/neuron/abstract_pynn_meanfield_model_standard.py b/spynnaker/pyNN/models/neuron/abstract_pynn_meanfield_model_standard.py new file mode 100644 index 00000000000..a3e6406dda7 --- /dev/null +++ b/spynnaker/pyNN/models/neuron/abstract_pynn_meanfield_model_standard.py @@ -0,0 +1,65 @@ +# Copyright (c) 2017-2019 The University of Manchester +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from .abstract_pynn_neuron_model import AbstractPyNNNeuronModel +from spynnaker.pyNN.models.neuron.implementations import MeanfieldImplStandard +from spinn_utilities.overrides import overrides + +_population_parameters = dict( + AbstractPyNNNeuronModel.default_population_parameters) +_population_parameters["n_steps_per_timestep"] = 1 + + +class AbstractPyNNMeanfieldModelStandard(AbstractPyNNNeuronModel): + """ A neuron model that follows the sPyNNaker standard composed model \ + pattern for point neurons. + """ + + __slots__ = [] + + default_population_parameters = _population_parameters + + def __init__( + self, model_name, binary, neuron_model, config, + mathsbox, input_type, synapse_type, threshold_type, additional_input_type=None): + """ + :param str model_name: Name of the model. + :param str binary: Name of the implementation executable. + :param AbstractNeuronModel neuron_model: The model of the neuron soma + :param AbstractInputType input_type: The model of synaptic input types + :param AbstractSynapseType synapse_type: + The model of the synapses' dynamics + :param AbstractThresholdType threshold_type: + The model of the firing threshold + :param additional_input_type: + The model (if any) of additional environmental inputs + :type additional_input_type: AbstractAdditionalInput or None + """ + super().__init__(MeanfieldImplStandard( + model_name, binary, neuron_model, config, mathsbox, input_type, + synapse_type, threshold_type, additional_input_type)) + + @overrides(AbstractPyNNNeuronModel.create_vertex, + additional_arguments={"n_steps_per_timestep"}) + def create_vertex( + self, n_neurons, label, constraints, spikes_per_second, + ring_buffer_sigma, incoming_spike_buffer_size, + n_steps_per_timestep, drop_late_spikes, splitter): + # pylint: disable=arguments-differ + self._model.n_steps_per_timestep = n_steps_per_timestep + return super().create_vertex( + n_neurons, label, constraints, spikes_per_second, + ring_buffer_sigma, incoming_spike_buffer_size, drop_late_spikes, + splitter) diff --git a/spynnaker/pyNN/models/neuron/builds/__init__.py b/spynnaker/pyNN/models/neuron/builds/__init__.py index feffbc1be10..fca83e4ca09 100644 --- a/spynnaker/pyNN/models/neuron/builds/__init__.py +++ b/spynnaker/pyNN/models/neuron/builds/__init__.py @@ -27,9 +27,11 @@ from .if_curr_delta import IFCurrDelta from .if_curr_exp_ca2_adaptive import IFCurrExpCa2Adaptive from .if_curr_exp_semd_base import IFCurrExpSEMDBase +from .meanfield_base import MeanfieldBase __all__ = ["EIFConductanceAlphaPopulation", "HHCondExp", "IFCondAlpha", "IFCondExpBase", "IFCurrAlpha", "IFCurrDualExpBase", "IFCurrExpBase", "IFFacetsConductancePopulation", "IzkCondExpBase", "IzkCurrExpBase", "IFCondExpStoc", - "IFCurrDelta", "IFCurrExpCa2Adaptive", "IFCurrExpSEMDBase", ] + "IFCurrDelta", "IFCurrExpCa2Adaptive", "IFCurrExpSEMDBase", + "MeanfieldBase", ] diff --git a/spynnaker/pyNN/models/neuron/builds/if_cond_exp_base.py b/spynnaker/pyNN/models/neuron/builds/if_cond_exp_base.py index c1cefe0a2d6..01c2374696b 100644 --- a/spynnaker/pyNN/models/neuron/builds/if_cond_exp_base.py +++ b/spynnaker/pyNN/models/neuron/builds/if_cond_exp_base.py @@ -15,8 +15,7 @@ from spynnaker.pyNN.models.neuron import AbstractPyNNNeuronModelStandard from spynnaker.pyNN.models.defaults import default_initial_values -from spynnaker.pyNN.models.neuron.neuron_models import ( - NeuronModelLeakyIntegrateAndFire) +from spynnaker.pyNN.models.neuron.neuron_models import (NeuronModelLeakyIntegrateAndFire) from spynnaker.pyNN.models.neuron.input_types import InputTypeConductance from spynnaker.pyNN.models.neuron.synapse_types import SynapseTypeExponential from spynnaker.pyNN.models.neuron.threshold_types import ThresholdTypeStatic diff --git a/spynnaker/pyNN/models/neuron/builds/meanfield_base.py b/spynnaker/pyNN/models/neuron/builds/meanfield_base.py new file mode 100644 index 00000000000..bd29e2eb2a4 --- /dev/null +++ b/spynnaker/pyNN/models/neuron/builds/meanfield_base.py @@ -0,0 +1,169 @@ +# Copyright (c) 2017-2019 The University of Manchester +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from spynnaker.pyNN.models.neuron.input_types import InputTypeConductance +from spynnaker.pyNN.models.neuron.neuron_models import MeanfieldModelEitn +from spynnaker.pyNN.models.neuron.neuron_models import Config +from spynnaker.pyNN.models.neuron.neuron_models import Mathsbox +from spynnaker.pyNN.models.neuron.synapse_types import SynapseTypeExponential +from spynnaker.pyNN.models.neuron.threshold_types import ThresholdTypeStatic +from spynnaker.pyNN.models.neuron import AbstractPyNNMeanfieldModelStandard +from spynnaker.pyNN.models.defaults import default_initial_values + +_IZK_THRESHOLD = 30.0 + + +class MeanfieldBase(AbstractPyNNMeanfieldModelStandard): + """ Izhikevich neuron model with conductance inputs. + + :param a: :math:`a` + :type a: float, iterable(float), ~pyNN.random.RandomDistribution + or (mapping) function + :param b: :math:`b` + :type b: float, iterable(float), ~pyNN.random.RandomDistribution + or (mapping) function + :param c: :math:`c` + :type c: float, iterable(float), ~pyNN.random.RandomDistribution + or (mapping) function + :param d: :math:`d` + :type d: float, iterable(float), ~pyNN.random.RandomDistribution + or (mapping) function + :param i_offset: :math:`I_{offset}` + :type i_offset: float, iterable(float), ~pyNN.random.RandomDistribution + or (mapping) function + :param u: :math:`u_{init} = \\delta V_{init}` + :type u: float, iterable(float), ~pyNN.random.RandomDistribution + or (mapping) function + :param v: :math:`v_{init} = V_{init}` + :type v: float, iterable(float), ~pyNN.random.RandomDistribution + or (mapping) function + :param tau_syn_E: :math:`\\tau^{syn}_e` + :type tau_syn_E: float, iterable(float), ~pyNN.random.RandomDistribution + or (mapping) function + :param tau_syn_I: :math:`\\tau^{syn}_i` + :type tau_syn_I: float, iterable(float), ~pyNN.random.RandomDistribution + or (mapping) function + :param e_rev_E: :math:`E^{rev}_e` + :type e_rev_E: float, iterable(float), ~pyNN.random.RandomDistribution + or (mapping) function + :param e_rev_I: :math:`E^{rev}_i` + :type e_rev_I: float, iterable(float), ~pyNN.random.RandomDistribution + or (mapping) function + :param isyn_exc: :math:`I^{syn}_e` + :type isyn_exc: float, iterable(float), ~pyNN.random.RandomDistribution + or (mapping) function + :param isyn_inh: :math:`I^{syn}_i` + :type isyn_inh: float, iterable(float), ~pyNN.random.RandomDistribution + or (mapping) function + """ + + # noinspection PyPep8Naming + @default_initial_values({"Ve", "muV", "sV", "muGn", "TvN", "Vthre", + "Fout_th", "err_func", "isyn_exc", "isyn_inh"}) + def __init__(self, + nbr=1, + a=0, + b=0, + tauw=1., + Trefrac=5.0, + Vreset=-65., + delta_v=-0.5, + ampnoise=0.0, + Timescale_inv=0.5, + Ve=0., + + pconnec=0.05, + q_exc=1.5, + q_inh=5.0, + Tsyn_exc=5., + Tsyn_inh=5., + Erev_exc=0., + Erev_inh=-80., + Ntot=10000, + gei=0.2, + ext_drive=2.5, + afferent_exc_fraction=1., + + Gl=10., + Cm=200., + El=-70., + + p0=-0.0515518, + p1=0.00455197, + p2=-0.00760625, + p3=0.00094851, + p4=0.001, + p5=-0.0009863, + p6=-0.0026474, + p7=-0.0135417, + p8=0.0028742, + p9=0.0029213, + p10=-0.014084, + + muV=0., + muV0=-0.06, + DmuV0=0.01, + + sV=0., + sV0=0.004, + DsV0=0.006, + + muGn=0., + + TvN=0., + TvN0=0.5, + DTvN0=1., + + Vthre=-50., + Fout_th=0., + + tau_syn_E=5.0, + tau_syn_I=5.0, + e_rev_E=0.0, + e_rev_I=-70.0, + + isyn_exc=0.0, + isyn_inh=0.0, + + sample=100, + err_func=0.): + # pylint: disable=too-many-arguments, too-many-locals + neuron_model = MeanfieldModelEitn(nbr, a, b, tauw, Trefrac, + Vreset, delta_v, ampnoise, + Timescale_inv, Ve) + config = Config(pconnec, q_exc, q_inh, + Tsyn_exc, Tsyn_inh, + Erev_exc, Erev_inh, + Ntot, gei, ext_drive, + afferent_exc_fraction, + Gl, Cm, El, + p0, p1, p2, p3, p4, p5, + p6, p7, p8, p9, p10, + muV, muV0,DmuV0, + sV, sV0, DsV0, + muGn, + TvN, TvN0, DTvN0, + Vthre, Fout_th) + mathsbox = Mathsbox(sample, err_func) + synapse_type = SynapseTypeExponential( + tau_syn_E, tau_syn_I, isyn_exc, isyn_inh) + input_type = InputTypeConductance(e_rev_E, e_rev_I) + threshold_type = ThresholdTypeStatic(_IZK_THRESHOLD) + + super().__init__( + model_name="meanfield_model_cond_fixing", binary="meanfield_model_cond_fixing.aplx", + neuron_model=neuron_model, config=config, mathsbox = mathsbox, + input_type=input_type, + synapse_type=synapse_type, threshold_type=threshold_type) diff --git a/spynnaker/pyNN/models/neuron/implementations/__init__.py b/spynnaker/pyNN/models/neuron/implementations/__init__.py index cf383ba9fd2..51fea46dd93 100644 --- a/spynnaker/pyNN/models/neuron/implementations/__init__.py +++ b/spynnaker/pyNN/models/neuron/implementations/__init__.py @@ -16,8 +16,10 @@ from .abstract_standard_neuron_component import AbstractStandardNeuronComponent from .abstract_neuron_impl import AbstractNeuronImpl from .neuron_impl_standard import NeuronImplStandard +from .meanfield_impl_standard import MeanfieldImplStandard from .ranged_dict_vertex_slice import RangedDictVertexSlice __all__ = [ "AbstractNeuronImpl", "AbstractStandardNeuronComponent", - "NeuronImplStandard", "RangedDictVertexSlice"] + "NeuronImplStandard", "MeanfieldImplStandard", + "RangedDictVertexSlice"] diff --git a/spynnaker/pyNN/models/neuron/implementations/meanfield_impl_standard.py b/spynnaker/pyNN/models/neuron/implementations/meanfield_impl_standard.py new file mode 100644 index 00000000000..7d79fc1a4a7 --- /dev/null +++ b/spynnaker/pyNN/models/neuron/implementations/meanfield_impl_standard.py @@ -0,0 +1,254 @@ +# Copyright (c) 2017-2019 The University of Manchester +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import numpy + +from data_specification.enums import DataType +from spinn_utilities.overrides import overrides +from spynnaker.pyNN.models.neuron.input_types import InputTypeConductance +from .abstract_neuron_impl import AbstractNeuronImpl +from spinn_front_end_common.utilities import globals_variables +from spinn_front_end_common.utilities.constants import BYTES_PER_WORD + +# The size of the n_steps_per_timestep parameter +_N_STEPS_PER_TIMESTEP_SIZE = 1 * BYTES_PER_WORD + +# The default number of steps per timestep +_DEFAULT_N_STEPS_PER_TIMESTEP = 1 + + +class MeanfieldImplStandard(AbstractNeuronImpl): + """ The standard componentised meanfield implementation. + """ + + __slots__ = [ + "__model_name", + "__binary", + "__neuron_model", + "__config", + "__mathsbox", + "__input_type", + "__synapse_type", + "__threshold_type", + "__additional_input_type", + "__components", + "__n_steps_per_timestep" + ] + + _RECORDABLES = ["Ve", "muV", "sV", "muGn", "TvN", "Vthre", + "Fout_th", "err_func", "gsyn_exc", "gsyn_inh"] + + _RECORDABLE_DATA_TYPES = { + "Ve": DataType.S1615, + "muV": DataType.S1615, + "sV": DataType.S1615, + "muGn": DataType.S1615, + "TvN": DataType.S1615, + "Vthre": DataType.S1615, + "Fout_th": DataType.S1615, + "err_func": DataType.S1615, + "gsyn_exc": DataType.S1615, + "gsyn_inh": DataType.S1615 + } + + _RECORDABLE_UNITS = { + 'Ve': 'mV', + 'muV': "uS", + 'sV': "uS", + 'TvN': 'mV', + 'Vthre': "uS", + 'Fout_th': "uS", + 'err_func': 'mV', + 'gsyn_exc': "uS", + 'gsyn_inh': "uS" + } + + def __init__( + self, model_name, binary, neuron_model, config, input_type, + mathsbox, synapse_type, threshold_type, additional_input_type=None): + """ + :param str model_name: + :param str binary: + :param AbstractNeuronModel neuron_model: + :param AbstractInputType input_type: + :param AbstractSynapseType synapse_type: + :param AbstractThresholdType threshold_type: + :param additional_input_type: + :type additional_input_type: AbstractAdditionalInput or None + """ + self.__model_name = model_name + self.__binary = binary + self.__neuron_model = neuron_model + self.__config = config + self.__mathsbox = mathsbox + self.__input_type = input_type + self.__synapse_type = synapse_type + self.__threshold_type = threshold_type + self.__additional_input_type = additional_input_type + self.__n_steps_per_timestep = _DEFAULT_N_STEPS_PER_TIMESTEP + + self.__components = [ + self.__neuron_model, self.__config, self.__mathsbox, self.__input_type, self.__threshold_type, + self.__synapse_type] + if self.__additional_input_type is not None: + self.__components.append(self.__additional_input_type) + + @property + def n_steps_per_timestep(self): + return self.__n_steps_per_timestep + + @n_steps_per_timestep.setter + def n_steps_per_timestep(self, n_steps_per_timestep): + self.__n_steps_per_timestep = n_steps_per_timestep + + @property + @overrides(AbstractNeuronImpl.model_name) + def model_name(self): + return self.__model_name + + @property + @overrides(AbstractNeuronImpl.binary_name) + def binary_name(self): + return self.__binary + + @overrides(AbstractNeuronImpl.get_n_cpu_cycles) + def get_n_cpu_cycles(self, n_neurons): + total = self.__neuron_model.get_n_cpu_cycles(n_neurons) + total += self.__synapse_type.get_n_cpu_cycles(n_neurons) + total += self.__config.get_n_cpu_cycles(n_neurons) + total += self.__input_type.get_n_cpu_cycles(n_neurons) + total += self.__mathsbox.get_n_cpu_cycles(n_neurons) + total += self.__threshold_type.get_n_cpu_cycles(n_neurons) + if self.__additional_input_type is not None: + total += self.__additional_input_type.get_n_cpu_cycles(n_neurons) + return total + + @overrides(AbstractNeuronImpl.get_dtcm_usage_in_bytes) + def get_dtcm_usage_in_bytes(self, n_neurons): + total = _N_STEPS_PER_TIMESTEP_SIZE + total += self.__neuron_model.get_dtcm_usage_in_bytes(n_neurons) + total += self.__synapse_type.get_dtcm_usage_in_bytes(n_neurons) + total += self.__config.get_dtcm_usage_in_bytes(n_neurons) + total += self.__input_type.get_dtcm_usage_in_bytes(n_neurons) + total += self.__mathsbox.get_dtcm_usage_in_bytes(n_neurons) + total += self.__threshold_type.get_dtcm_usage_in_bytes(n_neurons) + if self.__additional_input_type is not None: + total += self.__additional_input_type.get_dtcm_usage_in_bytes( + n_neurons) + return total + + @overrides(AbstractNeuronImpl.get_sdram_usage_in_bytes) + def get_sdram_usage_in_bytes(self, n_neurons): + total = _N_STEPS_PER_TIMESTEP_SIZE + total += self.__neuron_model.get_sdram_usage_in_bytes(n_neurons) + total += self.__synapse_type.get_sdram_usage_in_bytes(n_neurons) + total += self.__config.get_sdram_usage_in_bytes(n_neurons) + total += self.__input_type.get_sdram_usage_in_bytes(n_neurons) + total += self.__mathsbox.get_sdram_usage_in_bytes(n_neurons) + total += self.__threshold_type.get_sdram_usage_in_bytes(n_neurons) + if self.__additional_input_type is not None: + total += self.__additional_input_type.get_sdram_usage_in_bytes( + n_neurons) + return total + + @overrides(AbstractNeuronImpl.get_global_weight_scale) + def get_global_weight_scale(self): + return self.__input_type.get_global_weight_scale() + + @overrides(AbstractNeuronImpl.get_n_synapse_types) + def get_n_synapse_types(self): + return self.__synapse_type.get_n_synapse_types() + + @overrides(AbstractNeuronImpl.get_synapse_id_by_target) + def get_synapse_id_by_target(self, target): + return self.__synapse_type.get_synapse_id_by_target(target) + + @overrides(AbstractNeuronImpl.get_synapse_targets) + def get_synapse_targets(self): + return self.__synapse_type.get_synapse_targets() + + @overrides(AbstractNeuronImpl.get_recordable_variables) + def get_recordable_variables(self): + return self._RECORDABLES + + @overrides(AbstractNeuronImpl.get_recordable_units) + def get_recordable_units(self, variable): + return self._RECORDABLE_UNITS[variable] + + @overrides(AbstractNeuronImpl.get_recordable_data_types) + def get_recordable_data_types(self): + return self._RECORDABLE_DATA_TYPES + + @overrides(AbstractNeuronImpl.is_recordable) + def is_recordable(self, variable): + return variable in self._RECORDABLES + + @overrides(AbstractNeuronImpl.get_recordable_variable_index) + def get_recordable_variable_index(self, variable): + return self._RECORDABLES.index(variable) + + @overrides(AbstractNeuronImpl.add_parameters) + def add_parameters(self, parameters): + for component in self.__components: + component.add_parameters(parameters) + + @overrides(AbstractNeuronImpl.add_state_variables) + def add_state_variables(self, state_variables): + for component in self.__components: + component.add_state_variables(state_variables) + + @overrides(AbstractNeuronImpl.get_data) + def get_data(self, parameters, state_variables, vertex_slice): + # Work out the time step per step + ts = globals_variables.get_simulator().machine_time_step + ts /= self.__n_steps_per_timestep + items = [numpy.array([self.__n_steps_per_timestep], dtype="uint32")] + items.extend( + component.get_data(parameters, state_variables, vertex_slice, ts) + for component in self.__components) + return numpy.concatenate(items) + + @overrides(AbstractNeuronImpl.read_data) + def read_data( + self, data, offset, vertex_slice, parameters, state_variables): + offset += _N_STEPS_PER_TIMESTEP_SIZE + for component in self.__components: + offset = component.read_data( + data, offset, vertex_slice, parameters, state_variables) + return offset + + @overrides(AbstractNeuronImpl.get_units) + def get_units(self, variable): + for component in self.__components: + if component.has_variable(variable): + return component.get_units(variable) + + raise KeyError( + "The parameter {} does not exist in this input " + "conductance component".format(variable)) + + @property + @overrides(AbstractNeuronImpl.is_conductance_based) + def is_conductance_based(self): + return isinstance(self.__input_type, InputTypeConductance) + + def __getitem__(self, key): + # Find the property in the components... + for component in self.__components: + if hasattr(component, key): + return getattr(component, key) + # ... or fail + raise AttributeError("'{}' object has no attribute {}".format( + self.__class__.__name__, key)) diff --git a/spynnaker/pyNN/models/neuron/neuron_models/__init__.py b/spynnaker/pyNN/models/neuron/neuron_models/__init__.py index 2e5c36952d1..d69bda9c3e2 100644 --- a/spynnaker/pyNN/models/neuron/neuron_models/__init__.py +++ b/spynnaker/pyNN/models/neuron/neuron_models/__init__.py @@ -15,8 +15,12 @@ from .abstract_neuron_model import AbstractNeuronModel from .neuron_model_izh import NeuronModelIzh +from .meanfield_model_eitn import MeanfieldModelEitn +from .config import Config +from .mathsbox import Mathsbox from .neuron_model_leaky_integrate_and_fire import ( NeuronModelLeakyIntegrateAndFire) __all__ = ["AbstractNeuronModel", "NeuronModelIzh", - "NeuronModelLeakyIntegrateAndFire"] + "NeuronModelLeakyIntegrateAndFire", + "MeanfieldModelEitn", "Config", "Mathsbox", ] diff --git a/spynnaker/pyNN/models/neuron/neuron_models/abstract_input_type.py b/spynnaker/pyNN/models/neuron/neuron_models/abstract_input_type.py new file mode 100644 index 00000000000..3a5c2af216c --- /dev/null +++ b/spynnaker/pyNN/models/neuron/neuron_models/abstract_input_type.py @@ -0,0 +1,33 @@ +# Copyright (c) 2017-2019 The University of Manchester +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from spinn_utilities.abstract_base import AbstractBase, abstractmethod +from spynnaker.pyNN.models.neuron.implementations import ( + AbstractStandardNeuronComponent) + + +class AbstractInputType( + AbstractStandardNeuronComponent, metaclass=AbstractBase): + """ Represents a possible input type for a neuron model (e.g., current). + """ + __slots__ = () + + @abstractmethod + def get_global_weight_scale(self): + """ Get the global weight scaling value. + + :return: The global weight scaling value + :rtype: float + """ diff --git a/spynnaker/pyNN/models/neuron/neuron_models/config.py b/spynnaker/pyNN/models/neuron/neuron_models/config.py new file mode 100644 index 00000000000..800e5616a14 --- /dev/null +++ b/spynnaker/pyNN/models/neuron/neuron_models/config.py @@ -0,0 +1,598 @@ +# Copyright (c) 2017-2019 The University of Manchester +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +from spinn_utilities.overrides import overrides +from data_specification.enums import DataType +from spinn_front_end_common.utilities.constants import ( + MICRO_TO_MILLISECOND_CONVERSION) +from .abstract_neuron_model import AbstractNeuronModel +from .abstract_input_type import AbstractInputType +from spynnaker.pyNN.models.neuron.implementations import ( + AbstractStandardNeuronComponent) + +###--Syn and connect params--### +PCONNEC = "pconnec" +Q_EXC = "q_exc" +Q_INH = "q_inh" +TSYN_EXC = "Tsyn_exc" +TSYN_INH = "Tsyn_inh" +EREV_EXC = "Erev_exc" +EREV_INH = "Erev_inh" +NTOT = "Ntot" +GEI = "gei" +EXT_DRIVE = "ext_drive" +AFFERENT_EXC_FRACTION = "afferent_exc_fraction" + +GL = "Gl" +CM = "Cm" +EL = "El" + +###--transfert function inputs from 'data_test/'+NRN1+'_'+NTWK+'_fit.npy' --### +P0 = "p0" +P1 = "p1" +P2 = "p2" +P3 = "p3" +P4 = "p4" +P5 = "p5" +P6 = "p6" +P7 = "p7" +P8 = "p8" +P9 = "p9" +P10 = "p10" + +MUV = "muV" +MUV0 = "muV0" +DMUV0 = "DmuV0" + +SV = "sV" +SV0 = "sV0" +DSV0 = "DsV0" + +MUGN = "muGn" + +TVN = "TvN" +TVN0 = "TvN0" +DTVN0 = "DTvN0" + +VTHRE = "Vthre" + +FOUT_TH = "Fout_th" + +UNITS = { + ###--Syn connec--### + PCONNEC: "", + Q_EXC: "nS", + Q_INH: "nS", + TSYN_EXC: "", + TSYN_INH: "", + EREV_EXC: "mV", + EREV_INH: "mV", + NTOT: "", + GEI: "", + EXT_DRIVE: "", + AFFERENT_EXC_FRACTION: "", + GL: "Gl", + CM: "pF", + EL: "mV", + #TF inputs + P0 : "", + P1 : "", + P2 : "", + P3 : "", + P4 : "", + P5 : "", + P6 : "", + P7 : "", + P8 : "", + P9 : "", + P10 : "", + VTHRE: "mV", + MUV : "", + MUV0 : "", + DMUV0 : "", + SV : "", + SV0 : "", + DSV0 : "", + MUGN : "", + TVN : "", + TVN0 : "", + DTVN0 : "", + VTHRE : "", + FOUT_TH : "", +} + + +class Config(AbstractInputType): + """ Model of neuron due to Eugene M. Izhikevich et al + """ + __slots__ = [ + "__pconnec", "_q_exc", "_q_inh", "_Tsyn_exc", "_Tsyn_inh", + "_Erev_exc", "_Erev_inh", "_Ntot", + "_gei", "_ext_drive", "_afferent_exc_fraction", + "_Gl", "_Cm", "_El", + "_p0", "_p1", "_p2", "_p3", "_p4", "_p5", + "_p6", "_p7", "_p8", "_p9", "_p10", + "_Vthre", "_muV", "_muV0", "_DmuV0", "_sV", "_sV0", "_DsV0", + "_muGn", "_TvN", "_TvN0", "_DTvN0", "_Vthre", "_Fout_th", + ] + + def __init__(self, pconnec, + q_exc, q_inh, + Tsyn_exc, Tsyn_inh, + Erev_exc, Erev_inh, + Ntot, gei, ext_drive, + afferent_exc_fraction, + Gl, Cm, El, + p0, p1, p2, p3, p4, p5, + p6, p7, p8, p9, p10, + muV, muV0,DmuV0, + sV, sV0, DsV0, + muGn, + TvN, TvN0, DTvN0, + Vthre, Fout_th): + """ + :param a: :math:`a` + :type a: float, iterable(float), ~pyNN.random.RandomDistribution or + (mapping) function + :param b: :math:`b` + :type b: float, iterable(float), ~pyNN.random.RandomDistribution or + (mapping) function + :param c: :math:`c` + :type c: float, iterable(float), ~pyNN.random.RandomDistribution or + (mapping) function + :param d: :math:`d` + :type d: float, iterable(float), ~pyNN.random.RandomDistribution or + (mapping) function + :param v_init: :math:`v_{init}` + :type v_init: + float, iterable(float), ~pyNN.random.RandomDistribution or + (mapping) function + :param u_init: :math:`u_{init}` + :type u_init: + float, iterable(float), ~pyNN.random.RandomDistribution or + (mapping) function + :param i_offset: :math:`I_{offset}` + :type i_offset: + float, iterable(float), ~pyNN.random.RandomDistribution or + (mapping) function + """ + super().__init__( + + [###--syn and connect--### + DataType.S1615, #pconnec + DataType.S1615, #q_exc + DataType.S1615, #q_inh + DataType.S1615, #Tsyn_exc + DataType.S1615, #Tsyn_inh + DataType.S1615, #Erev_exc + DataType.S1615, #Erev_inh + DataType.UINT32, #Ntot + DataType.S1615, #gei + DataType.S1615, #ext_drive + DataType.S1615, #afferent_exc_fraction + DataType.S1615, #Gm + DataType.S1615, #Cl + DataType.S1615, #El + ###--TF inputs--### + DataType.S031, #p0 + DataType.S031, #p1 + DataType.S031, #p2 + DataType.S031, #p3 + DataType.S031, #p4 + DataType.S031, #p5 + DataType.S031, #p6 + DataType.S031, #p7 + DataType.S031, #p8 + DataType.S031, #p9 + DataType.S031, #p10 + DataType.S1615, # muV + DataType.S1615, # muV0 + DataType.S1615, # DmuV0 + DataType.S1615, # sV + DataType.S1615, # sV0 + DataType.S1615, # DsV0 + DataType.S1615, # muGn + DataType.S1615, # TvN + DataType.S1615, # TvN0 + DataType.S1615, # DTvN0 + DataType.S1615, # Vthre + DataType.S1615]) # Fout_th + + self.__pconnec = pconnec + self._q_exc = q_exc + self._q_inh = q_inh + self._Tsyn_exc = Tsyn_exc + self._Tsyn_inh = Tsyn_inh + self._Erev_exc = Erev_exc + self._Erev_inh = Erev_inh + self._Ntot = Ntot + self._gei = gei + self._ext_drive = ext_drive + self._afferent_exc_fraction = afferent_exc_fraction + self._Gl = Gl + self._Cm = Cm + self._El = El + self._p0 = p0 + self._p1 = p1 + self._p2 = p2 + self._p3 = p3 + self._p4 = p4 + self._p5 = p5 + self._p6 = p6 + self._p7 = p7 + self._p8 = p8 + self._p9 = p9 + self._p10 = p10 + self._muV = muV + self._muV0 = muV0 + self._DmuV0 = DmuV0 + self._sV = sV + self._sV0 = sV0 + self._DsV0 = DsV0 + self._muGn = muGn + self._TvN = TvN + self._TvN0 = TvN0 + self._DTvN0 = DTvN0 + self._Vthre = Vthre + self._Fout_th = Fout_th + + @overrides(AbstractStandardNeuronComponent.get_n_cpu_cycles) + def get_n_cpu_cycles(self, n_neurons): + # A bit of a guess + return 150 * n_neurons + + @overrides(AbstractStandardNeuronComponent.add_parameters) + def add_parameters(self, parameters): + ###--syn and connec--### + parameters[PCONNEC] = self.__pconnec + parameters[Q_EXC] = self._q_exc + parameters[Q_INH] = self._q_inh + parameters[TSYN_EXC] = self._Tsyn_exc + parameters[TSYN_INH] = self._Tsyn_inh + parameters[EREV_EXC] = self._Erev_exc + parameters[EREV_INH] = self._Erev_inh + parameters[NTOT] = self._Ntot + parameters[GEI] = self._gei + parameters[EXT_DRIVE] = self._ext_drive + parameters[AFFERENT_EXC_FRACTION] = self._afferent_exc_fraction + parameters[GL] = self._Gl + parameters[CM] = self._Cm + parameters[EL] = self._El + ###--TF inputs--### + parameters[P0] = self._p0 + parameters[P1] = self._p1 + parameters[P2] = self._p2 + parameters[P3] = self._p3 + parameters[P4] = self._p4 + parameters[P5] = self._p5 + parameters[P6] = self._p6 + parameters[P7] = self._p7 + parameters[P8] = self._p8 + parameters[P9] = self._p9 + parameters[P10] = self._p10 + parameters[MUV0] = self._muV0 + parameters[DMUV0] = self._DmuV0 + parameters[SV0] = self._sV0 + parameters[DSV0] = self._DsV0 + parameters[TVN0] = self._TvN0 + parameters[DTVN0] = self._DTvN0 + + @overrides(AbstractStandardNeuronComponent.add_state_variables) + def add_state_variables(self, state_variables): + state_variables[MUV] = self._muV + state_variables[SV] = self._sV + state_variables[MUGN] = self._muGn + state_variables[TVN] = self._TvN + state_variables[VTHRE] = self._Vthre + state_variables[FOUT_TH] = self._Fout_th + + @overrides(AbstractStandardNeuronComponent.get_units) + def get_units(self, variable): + return UNITS[variable] + + @overrides(AbstractStandardNeuronComponent.has_variable) + def has_variable(self, variable): + return variable in UNITS + + @overrides(AbstractNeuronModel.get_global_values) + def get_global_values(self, ts): + # pylint: disable=arguments-differ + pass + + @overrides(AbstractStandardNeuronComponent.get_values) + def get_values(self, parameters, state_variables, vertex_slice, ts): + """ + :param ts: machine time step + """ + # pylint: disable=arguments-differ + + # Add the rest of the data + return [parameters[PCONNEC],###syn and connect + parameters[Q_EXC], + parameters[Q_INH], + parameters[TSYN_EXC], + parameters[TSYN_INH], + parameters[EREV_EXC], + parameters[EREV_INH], + parameters[NTOT], + parameters[GEI], + parameters[EXT_DRIVE], + parameters[AFFERENT_EXC_FRACTION], + parameters[GL], + parameters[CM], + parameters[EL], + parameters[P0],#TF input + parameters[P1], + parameters[P2], + parameters[P3], + parameters[P4], + parameters[P5], + parameters[P6], + parameters[P7], + parameters[P8], + parameters[P9], + parameters[P10], + state_variables[MUV], + parameters[MUV0], + parameters[DMUV0], + state_variables[SV], + parameters[SV0], + parameters[DSV0], + state_variables[MUGN], + state_variables[TVN], + parameters[TVN0], + parameters[DTVN0], + state_variables[VTHRE], + state_variables[FOUT_TH] + ] + + @overrides(AbstractStandardNeuronComponent.update_values) + def update_values(self, values, parameters, state_variables): + + # Decode the values + (__pconnec, _q_exc, _q_inh, _Tsyn_exc, _Tsyn_inh, + _Erev_exc, _Erev_inh, _Ntot, _gei, _ext_drive, + _afferent_exc_fraction, + _Gl, _Cm, _El, + _p0, _p1, _p2, _p3, _p4, + _p5, _p6, _p7, _p8, _p9, _p10, + muV, _muV0, _DmuV0, + sV, _sV0, _DsV0, + muGn, + TvN, _TvN0, _DTvN0, + Vthre, Fout_th) = values + + # Copy the changed data only + state_variables[MUV] = muV + state_variables[SV] = sV + state_variables[MUGN] = muGn + state_variables[TVN] = TvN + state_variables[VTHRE] = Vthre + state_variables[FOUT_TH] = Fout_th + + @overrides(AbstractInputType.get_global_weight_scale) + def get_global_weight_scale(self): + return 1024.0 + +######################## +###--syn and connec--### +######################## + @property + def pconnec(self): + return self.__pconnec + + @property + def q_exc(self): + return self._q_exc + + @property + def q_inh(self): + return self._q_inh + + @property + def Tsyn_exc(self): + return self._Tsyn_exc + + @property + def Tsyn_inh(self): + return self._Tsyn_inh + + @property + def Erev_exc(self): + return self._Erev_exc + + @property + def Erev_inh(self): + return self._Erev_inh + + @Erev_inh.setter + def Erev_inh(self, Erev_inh): + self._Erev_inh = Erev_inh + + @property + def Ntot(self): + return self._Ntot + + @property + def gei(self): + return self._gei + + @property + def ext_drive(self): + return self._ext_drive + + @property + def afferent_exc_fraction(self): + return self._afferent_exc_fraction + + @property + def Gl(self): + return self._Gl + + @property + def Cm(self): + return self._Cm + + @property + def El(self): + return self._El + +################### +###--TF inputs--### +################### + + @property + def p0(self): + return self._p0 + + @property + def p1(self): + return self._p1 + + @property + def p2(self): + return self._p2 + + @property + def p3(self): + return self._p3 + + @property + def p4(self): + return self._p4 + + @property + def p5(self): + return self._p5 + + @property + def p6(self): + return self._p6 + + @property + def p6(self): + return self._p6 + + @property + def p7(self): + return self._p7 + + @property + def p8(self): + return self._p8 + + @property + def p9(self): + return self._p9 + + @property + def p10(self): + return self._p10 + + + @property + def muV(self): + """ Settable model parameter: :math:`a` + + :rtype: float + """ + return self._muV + + @property + def muV0(self): + """ Settable model parameter: :math:`b` + + :rtype: float + """ + return self._muV0 + + @property + def DmuV0(self): + """ Settable model parameter: :math:`c` + + :rtype: float + """ + return self._DmuV0 + + @property + def sV(self): + """ Settable model parameter: :math:`d` + + :rtype: float + """ + return self._sV + + @property + def sV0(self): + """ Settable model parameter: :math:`d` + + :rtype: float + """ + return self._sV0 + + @property + def DsV0(self): + """ Settable model parameter: :math:`d` + + :rtype: float + """ + return self._DsV0 + + @property + def muGn(self): + """ Settable model parameter: :math:`d` + + :rtype: float + """ + return self._muGn + + @property + def TvN(self): + """ Settable model parameter: :math:`d` + + :rtype: float + """ + return self._TvN + + @property + def TvN0(self): + """ Settable model parameter: :math:`d` + + :rtype: float + """ + return self._TvN0 + + @property + def DTvN0(self): + """ Settable model parameter: :math:`d` + + :rtype: float + """ + return self._DTvN0 + + @property + def Vthre(self): + """ Settable model parameter: :math:`d` + + :rtype: float + """ + return self._Vthre + + @property + def Fout_th(self): + """ Settable model parameter: :math:`d` + + :rtype: float + """ + return self._Fout_th \ No newline at end of file diff --git a/spynnaker/pyNN/models/neuron/neuron_models/mathsbox.py b/spynnaker/pyNN/models/neuron/neuron_models/mathsbox.py new file mode 100644 index 00000000000..3da912979ea --- /dev/null +++ b/spynnaker/pyNN/models/neuron/neuron_models/mathsbox.py @@ -0,0 +1,123 @@ +# Copyright (c) 2017-2019 The University of Manchester +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +from spinn_utilities.overrides import overrides +from data_specification.enums import DataType +from spinn_front_end_common.utilities.constants import ( + MICRO_TO_MILLISECOND_CONVERSION) +from .abstract_neuron_model import AbstractNeuronModel +from .abstract_input_type import AbstractInputType +from spynnaker.pyNN.models.neuron.implementations import ( + AbstractStandardNeuronComponent) + +###--Meanfield Params--### +SAMPLE = "sample" +ERR_FUNC = "err_func" + +UNITS = { + ###--Meanfield--### + SAMPLE: "", + ERR_FUNC: "", +} + + +class Mathsbox(AbstractInputType): + """ Model of meanfield due to Destehexe et al + """ + __slots__ = ["_sample", "_err_func"] + + def __init__(self, sample, err_func): + """ + :param a: :math:`a` + :type a: float, iterable(float), ~pyNN.random.RandomDistribution or + (mapping) function + :param b: :math:`b` + :type b: float, iterable(float), ~pyNN.random.RandomDistribution or + (mapping) function + + """ + super().__init__( + [DataType.UINT32, #sample + DataType.S1615]) # error fonction + self._sample = sample + self._err_func = err_func + + @overrides(AbstractStandardNeuronComponent.get_n_cpu_cycles) + def get_n_cpu_cycles(self, n_neurons): + # A bit of a guess + return 150 * n_neurons + + @overrides(AbstractStandardNeuronComponent.add_parameters) + def add_parameters(self, parameters): + ###--neuron--### + parameters[SAMPLE] = self._sample + + @overrides(AbstractStandardNeuronComponent.add_state_variables) + def add_state_variables(self, state_variables): + state_variables[ERR_FUNC] = self._err_func + + @overrides(AbstractStandardNeuronComponent.get_units) + def get_units(self, variable): + return UNITS[variable] + + @overrides(AbstractStandardNeuronComponent.has_variable) + def has_variable(self, variable): + return variable in UNITS + + @overrides(AbstractNeuronModel.get_global_values) + def get_global_values(self, ts): + # pylint: disable=arguments-differ + pass + + @overrides(AbstractStandardNeuronComponent.get_values) + def get_values(self, parameters, state_variables, vertex_slice, ts): + """ + :param ts: machine time step + """ + # pylint: disable=arguments-differ + + # Add the rest of the data + return [ + parameters[SAMPLE], state_variables[ERR_FUNC], + ] + + @overrides(AbstractStandardNeuronComponent.update_values) + def update_values(self, values, parameters, state_variables): + + # Decode the values + _sample = values + + # Copy the changed data only + state_variables[ERR_FUNC] = err_func + #state_variables[U] = u + + @overrides(AbstractInputType.get_global_weight_scale) + def get_global_weight_scale(self): + return 1024.0 + +################ +###--Meanfield--### +################ + + @property + def sample(self): + return self._sample + + + @property + def err_func(self): + return self._err_func + + + \ No newline at end of file diff --git a/spynnaker/pyNN/models/neuron/neuron_models/meanfield_model_eitn.py b/spynnaker/pyNN/models/neuron/neuron_models/meanfield_model_eitn.py new file mode 100644 index 00000000000..1431dc5c538 --- /dev/null +++ b/spynnaker/pyNN/models/neuron/neuron_models/meanfield_model_eitn.py @@ -0,0 +1,224 @@ +# Copyright (c) 2017-2019 The University of Manchester +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +from spinn_utilities.overrides import overrides +from data_specification.enums import DataType +from spinn_front_end_common.utilities.constants import ( + MICRO_TO_MILLISECOND_CONVERSION) +from .abstract_neuron_model import AbstractNeuronModel +from spynnaker.pyNN.models.neuron.implementations import ( + AbstractStandardNeuronComponent) + +###--Meanfield Params--### +NBR = "nbr" +A = "a" +B = "b" +TAUW = "tauw" +TREFRAC = "Trefrac" +VRESET = "Vreset" +DELTA_V = "delta_v" +AMPNOISE = "ampnoise" +TIMESCALE_INV = "Timescale_inv" +VE = "Ve" + +UNITS = { + ###--Meanfield--### + NBR: "", + A: "nS", + B: "nS", + TAUW: "ms", + TREFRAC: "ms", + VRESET: "mV", + DELTA_V: "mV", + AMPNOISE: "Hz", + TIMESCALE_INV: "Hz", + VE: "Hz", +} + + +class MeanfieldModelEitn(AbstractNeuronModel): + """ Model of meanfield due to Destehexe et al + """ + __slots__ = [ + "_nbr", "_a", "_b", "_tauw", "_Trefrac", "_Vreset", "_delta_v", "_ampnoise", "_Timescale_inv", "_Ve_init" + ] + + def __init__(self, nbr, a, b, tauw, + Trefrac, Vreset, delta_v, + ampnoise, Timescale_inv, Ve_init): + """ + :param a: :math:`a` + :type a: float, iterable(float), ~pyNN.random.RandomDistribution or + (mapping) function + :param b: :math:`b` + :type b: float, iterable(float), ~pyNN.random.RandomDistribution or + (mapping) function + :param c: :math:`c` + :type c: float, iterable(float), ~pyNN.random.RandomDistribution or + (mapping) function + :param d: :math:`d` + :type d: float, iterable(float), ~pyNN.random.RandomDistribution or + (mapping) function + :param v_init: :math:`v_{init}` + :type v_init: + float, iterable(float), ~pyNN.random.RandomDistribution or + (mapping) function + :param u_init: :math:`u_{init}` + :type u_init: + float, iterable(float), ~pyNN.random.RandomDistribution or + (mapping) function + :param i_offset: :math:`I_{offset}` + :type i_offset: + float, iterable(float), ~pyNN.random.RandomDistribution or + (mapping) function + """ + super().__init__( + [DataType.UINT32, #nbr + DataType.S1615, #a + DataType.S1615, #b + DataType.S1615, #tauw + DataType.S1615, #Trefrac + DataType.S1615, #Vreset + DataType.S1615, #delta_v + DataType.S1615, #ampnoise + DataType.S1615, #Timescale_inv + DataType.S1615, #Ve + DataType.S1615], # this_h (= machine_time_step) + [DataType.S1615]) # machine_time_step + self._nbr = nbr + self._a = a + self._b = b + self._tauw = tauw + self._Trefrac = Trefrac + self._Vreset =Vreset + self._delta_v = delta_v + self._ampnoise = ampnoise + self._Timescale_inv = Timescale_inv + self._Ve_init = Ve_init + + @overrides(AbstractStandardNeuronComponent.get_n_cpu_cycles) + def get_n_cpu_cycles(self, n_neurons): + # A bit of a guess + return 150 * n_neurons + + @overrides(AbstractStandardNeuronComponent.add_parameters) + def add_parameters(self, parameters): + ###--neuron--### + parameters[NBR] = self._nbr + parameters[A] = self._a + parameters[B] = self._b + parameters[TAUW] = self._tauw + parameters[TREFRAC] = self._Trefrac + parameters[VRESET] = self._Vreset + parameters[DELTA_V] = self._delta_v + parameters[AMPNOISE] = self._ampnoise + parameters[TIMESCALE_INV] = self._Timescale_inv + + @overrides(AbstractStandardNeuronComponent.add_state_variables) + def add_state_variables(self, state_variables): + state_variables[VE] = self._Ve_init + #state_variables[U] = self.__u_init + + @overrides(AbstractStandardNeuronComponent.get_units) + def get_units(self, variable): + return UNITS[variable] + + @overrides(AbstractStandardNeuronComponent.has_variable) + def has_variable(self, variable): + return variable in UNITS + + @overrides(AbstractNeuronModel.get_global_values) + def get_global_values(self, ts): + # pylint: disable=arguments-differ + return [float(ts) / MICRO_TO_MILLISECOND_CONVERSION] + + @overrides(AbstractStandardNeuronComponent.get_values) + def get_values(self, parameters, state_variables, vertex_slice, ts): + """ + :param ts: machine time step + """ + # pylint: disable=arguments-differ + + # Add the rest of the data + return [ + parameters[NBR],parameters[A],parameters[B],parameters[TAUW], + parameters[TREFRAC], + parameters[VRESET],parameters[DELTA_V],parameters[AMPNOISE], + parameters[TIMESCALE_INV], + state_variables[VE], + float(ts) / MICRO_TO_MILLISECOND_CONVERSION + ] + + @overrides(AbstractStandardNeuronComponent.update_values) + def update_values(self, values, parameters, state_variables): + + # Decode the values + (_nbr, _a, _b, _tauw, + _Trefrac, _Vreset, _delta_v, + _ampnoise, _Timescale_inv, Ve, _this_h) = values + + # Copy the changed data only + state_variables[VE] = Ve + #state_variables[U] = u + +################ +###--Meanfield--### +################ + + @property + def nbr(self): + return self._nbr + + + @property + def a(self): + return self._a + + @property + def b(self): + return self._b + + @property + def tauw(self): + return self._tauw + + @property + def Trefrac(self): + return self._Trefrac + + @property + def Vreset(self): + return self._Vreset + + @property + def delta_v(self): + return self._delta_v + + @property + def ampnoise(self): + return self._ampnoise + + @property + def Timescale_inv(self): + return self._Timescale_inv + + @property + def Ve_init(self): + """ Settable model parameter: :math:`V_{e}` + + :rtype: float + """ + return self._Ve_init + + \ No newline at end of file diff --git a/spynnaker8/__init__.py b/spynnaker8/__init__.py index b480f078bdd..a78d43ea65a 100644 --- a/spynnaker8/__init__.py +++ b/spynnaker8/__init__.py @@ -95,6 +95,9 @@ # noinspection PyUnresolvedReferences from spynnaker.pyNN.models.spike_source.spike_source_poisson import ( SpikeSourcePoisson) +# noinspection PyUnresolvedReferences +from spynnaker.pyNN.models.neuron.builds.meanfield_base import ( + MeanfieldBase as Meanfield) # pops # noinspection PyUnresolvedReferences From d02cfb34fdb2c6bc82ff1d817a74c1decf20e0a0 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Mon, 4 Oct 2021 13:03:53 +0100 Subject: [PATCH 02/44] fixed the check for early spikes --- .../pyNN/models/spike_source/spike_source_array_vertex.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spynnaker/pyNN/models/spike_source/spike_source_array_vertex.py b/spynnaker/pyNN/models/spike_source/spike_source_array_vertex.py index 9688911622d..7ea62e36c42 100644 --- a/spynnaker/pyNN/models/spike_source/spike_source_array_vertex.py +++ b/spynnaker/pyNN/models/spike_source/spike_source_array_vertex.py @@ -105,7 +105,7 @@ def _to_early_spikes_single_list(self, spike_times): """ current_time = get_simulator().get_current_time() for i in range(len(spike_times)): - if spike_times[i] > current_time: + if spike_times[i] < current_time: logger.warning( "SpikeSourceArray {} has spike_times that are lower than " "the current time {} For example {} - " @@ -125,7 +125,7 @@ def _check_spikes_double_list(self, spike_times): for neuron_id in range(0, self.n_atoms): id_times = spike_times[neuron_id] for i in range(len(id_times)): - if id_times[i] > current_time: + if id_times[i] < current_time: logger.warning( "SpikeSourceArray {} has spike_times that are lower " "than the current time {} For example {} - " From 2dd48eee1feaf2f3b297d9d557d474012e5ca438 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Tue, 5 Oct 2021 11:02:13 +0100 Subject: [PATCH 03/44] remove extract_iobuf_during_run flag --- .../spynnaker.cfg | 1 - .../__init__.py | 14 ------ .../spynnaker.cfg | 6 --- .../test_noIobuf_during_run.py | 47 ------------------- .../test_iobuf/test_multirun/spynnaker.cfg | 1 - .../spynnaker.cfg | 1 - .../test_only_binaries_recorded/spynnaker.cfg | 1 - .../test_master_pop/spynnaker.cfg | 1 - 8 files changed, 72 deletions(-) delete mode 100644 spynnaker_integration_tests/test_iobuf/test_iobuf_without_during_run_flag/__init__.py delete mode 100644 spynnaker_integration_tests/test_iobuf/test_iobuf_without_during_run_flag/spynnaker.cfg delete mode 100644 spynnaker_integration_tests/test_iobuf/test_iobuf_without_during_run_flag/test_noIobuf_during_run.py diff --git a/spynnaker_integration_tests/test_iobuf/test_cores_and_binaries_recorded/spynnaker.cfg b/spynnaker_integration_tests/test_iobuf/test_cores_and_binaries_recorded/spynnaker.cfg index 03274b437a8..54e39bd86f9 100644 --- a/spynnaker_integration_tests/test_iobuf/test_cores_and_binaries_recorded/spynnaker.cfg +++ b/spynnaker_integration_tests/test_iobuf/test_cores_and_binaries_recorded/spynnaker.cfg @@ -2,7 +2,6 @@ extract_iobuf = True extract_iobuf_from_cores = 0,0,2 extract_iobuf_from_binary_types = IF_curr_exp.aplx,reverse_iptag_multicast_source.aplx -extract_iobuf_during_run = True clear_iobuf_during_run = True [Mapping] diff --git a/spynnaker_integration_tests/test_iobuf/test_iobuf_without_during_run_flag/__init__.py b/spynnaker_integration_tests/test_iobuf/test_iobuf_without_during_run_flag/__init__.py deleted file mode 100644 index d358f58a868..00000000000 --- a/spynnaker_integration_tests/test_iobuf/test_iobuf_without_during_run_flag/__init__.py +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright (c) 2017-2019 The University of Manchester -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . diff --git a/spynnaker_integration_tests/test_iobuf/test_iobuf_without_during_run_flag/spynnaker.cfg b/spynnaker_integration_tests/test_iobuf/test_iobuf_without_during_run_flag/spynnaker.cfg deleted file mode 100644 index b8773f67d85..00000000000 --- a/spynnaker_integration_tests/test_iobuf/test_iobuf_without_during_run_flag/spynnaker.cfg +++ /dev/null @@ -1,6 +0,0 @@ -[Reports] -extract_iobuf = True -extract_iobuf_during_run = False -clear_iobuf_during_run = False -extract_iobuf_from_cores = ALL -extract_iobuf_from_binary_types = None diff --git a/spynnaker_integration_tests/test_iobuf/test_iobuf_without_during_run_flag/test_noIobuf_during_run.py b/spynnaker_integration_tests/test_iobuf/test_iobuf_without_during_run_flag/test_noIobuf_during_run.py deleted file mode 100644 index 1252d2acb0c..00000000000 --- a/spynnaker_integration_tests/test_iobuf/test_iobuf_without_during_run_flag/test_noIobuf_during_run.py +++ /dev/null @@ -1,47 +0,0 @@ -# Copyright (c) 2017-2019 The University of Manchester -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -""" -Synfirechain-like example -""" -import os -from spinn_front_end_common.utilities import globals_variables -import spynnaker8 as sim -from spinnaker_testbase import BaseTestCase - - -class TestNoIobufDuringRun(BaseTestCase): - - def check_for_iobufs(self, prov_path): - return any("iobuf" in filename and ".txt" in filename - for filename in os.listdir(prov_path)) - - def do_run(self): - sim.setup(timestep=1.0, min_delay=1.0) - sim.Population(10, sim.IF_curr_exp(), label='pop_1') - sim.run(500) - prov_path = globals_variables.app_provenance_file_path() - - self.assertFalse(self.check_for_iobufs(prov_path)) - sim.end() - self.assertTrue(self.check_for_iobufs(prov_path)) - - def test_do_run(self): - self.runsafe(self.do_run) - - -if __name__ == '__main__': - x = TestNoIobufDuringRun() - x.do_run() diff --git a/spynnaker_integration_tests/test_iobuf/test_multirun/spynnaker.cfg b/spynnaker_integration_tests/test_iobuf/test_multirun/spynnaker.cfg index f34603605a9..1001dd80171 100644 --- a/spynnaker_integration_tests/test_iobuf/test_multirun/spynnaker.cfg +++ b/spynnaker_integration_tests/test_iobuf/test_multirun/spynnaker.cfg @@ -1,6 +1,5 @@ [Reports] extract_iobuf = True -extract_iobuf_during_run = True extract_iobuf_from_cores = ALL extract_iobuf_from_binary_types = None clear_iobuf_during_run = True \ No newline at end of file diff --git a/spynnaker_integration_tests/test_iobuf/test_none_but_active_recorded/spynnaker.cfg b/spynnaker_integration_tests/test_iobuf/test_none_but_active_recorded/spynnaker.cfg index 4aedff783d5..0fda5cbca27 100644 --- a/spynnaker_integration_tests/test_iobuf/test_none_but_active_recorded/spynnaker.cfg +++ b/spynnaker_integration_tests/test_iobuf/test_none_but_active_recorded/spynnaker.cfg @@ -1,6 +1,5 @@ [Reports] extract_iobuf = True extract_iobuf_from_cores = None -extract_iobuf_during_run = True extract_iobuf_from_binary_types = None clear_iobuf_during_run = False \ No newline at end of file diff --git a/spynnaker_integration_tests/test_iobuf/test_only_binaries_recorded/spynnaker.cfg b/spynnaker_integration_tests/test_iobuf/test_only_binaries_recorded/spynnaker.cfg index 063a67b8951..c8dda9b301d 100644 --- a/spynnaker_integration_tests/test_iobuf/test_only_binaries_recorded/spynnaker.cfg +++ b/spynnaker_integration_tests/test_iobuf/test_only_binaries_recorded/spynnaker.cfg @@ -2,6 +2,5 @@ extract_iobuf = True extract_iobuf_from_cores = None extract_iobuf_from_binary_types = reverse_iptag_multicast_source.aplx -extract_iobuf_during_run = True clear_iobuf_during_run = True diff --git a/spynnaker_integration_tests/test_master_pop/spynnaker.cfg b/spynnaker_integration_tests/test_master_pop/spynnaker.cfg index 4823dd470a4..4ce68cafb25 100644 --- a/spynnaker_integration_tests/test_master_pop/spynnaker.cfg +++ b/spynnaker_integration_tests/test_master_pop/spynnaker.cfg @@ -2,7 +2,6 @@ extract_iobuf = True extract_iobuf_from_cores = 0,0,2 extract_iobuf_from_binary_types = IF_curr_exp.aplx,reverse_iptag_multicast_source.aplx -extract_iobuf_during_run = True clear_iobuf_during_run = True [Mapping] From 53e62fc0fc348eeaa9024ba182ff445188090570 Mon Sep 17 00:00:00 2001 From: Donal Fellows Date: Tue, 5 Oct 2021 13:02:30 +0100 Subject: [PATCH 04/44] Fix a whole bunch of minor warnings in the documentation build There's apparently also a crash, but I can't reproduce that locally --- neural_modelling/Doxyfile | 13 --------- .../bit_field_expander/bit_field_expander.c | 2 +- .../src/delay_extension/delay_extension.c | 12 ++++++-- neural_modelling/src/neuron/c_main_synapses.c | 3 ++ .../src/neuron/implementations/neuron_impl.h | 4 +-- .../neuron_impl_external_devices.h | 4 +-- .../implementations/neuron_impl_standard.h | 4 +++ .../src/neuron/models/neuron_model_izh_impl.h | 28 +++++++++++++++++-- .../src/neuron/models/neuron_model_lif_impl.h | 23 +++++++++++++++ neural_modelling/src/neuron/neuron.c | 4 +-- .../population_table/population_table.h | 1 + .../population_table_binary_search_impl.c | 8 +++--- .../src/neuron/spike_processing.c | 3 -- .../src/neuron/spike_processing.h | 7 ++--- .../src/neuron/spike_processing_fast.h | 3 +- .../synaptogenesis/sp_structs.h | 1 - .../synaptogenesis/topographic_map_impl.c | 14 +++++++--- .../synaptogenesis_dynamics.h | 2 ++ neural_modelling/src/neuron/synapse_row.h | 28 +++++++++++-------- .../src/neuron/synapse_types/synapse_types.h | 7 +++-- .../synapse_types/synapse_types_alpha_impl.h | 2 ++ .../synapse_types/synapse_types_delta_impl.h | 2 ++ ...e_types_dual_excitatory_exponential_impl.h | 2 ++ .../synapse_types_exponential_impl.h | 2 ++ .../synapse_types/synapse_types_semd_impl.h | 2 ++ neural_modelling/src/neuron/synapses.c | 4 ++- neural_modelling/src/neuron/synapses.h | 2 +- .../src/synapse_expander/delay_expander.c | 18 ++++++------ 28 files changed, 135 insertions(+), 70 deletions(-) diff --git a/neural_modelling/Doxyfile b/neural_modelling/Doxyfile index 6f171bf99b7..b7754e76cc0 100644 --- a/neural_modelling/Doxyfile +++ b/neural_modelling/Doxyfile @@ -237,12 +237,6 @@ TAB_SIZE = 4 ALIASES = -# This tag can be used to specify a number of word-keyword mappings (TCL only). -# A mapping has the form "name=value". For example adding "class=itcl::class" -# will allow you to use the command class in the itcl::class meaning. - -TCL_SUBST = - # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For # instance, some of the names that are used will be different. The list of all @@ -993,13 +987,6 @@ VERBATIM_HEADERS = YES ALPHABETICAL_INDEX = YES -# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in -# which the alphabetical index list will be split. -# Minimum value: 1, maximum value: 20, default value: 5. -# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. - -COLS_IN_ALPHA_INDEX = 5 - # In case all classes in a project start with a common prefix, all classes will # be put under the same header in the alphabetical index. The IGNORE_PREFIX tag # can be used to specify a prefix (or a list of prefixes) that should be ignored diff --git a/neural_modelling/src/bit_field_expander/bit_field_expander.c b/neural_modelling/src/bit_field_expander/bit_field_expander.c index bcbea259455..f27b320878d 100644 --- a/neural_modelling/src/bit_field_expander/bit_field_expander.c +++ b/neural_modelling/src/bit_field_expander/bit_field_expander.c @@ -283,7 +283,7 @@ bool process_synaptic_row(synaptic_row_t row) { } //! \brief Do an SDRAM read to get synaptic row. -//! \param[in] row_address: the SDRAM address to read +//! \param[in] row: the SDRAM address to read //! \param[in] n_bytes_to_transfer: //! how many bytes to read to get the synaptic row //! \return Whether there is target diff --git a/neural_modelling/src/delay_extension/delay_extension.c b/neural_modelling/src/delay_extension/delay_extension.c index 2d276b46037..3f405c9cf16 100644 --- a/neural_modelling/src/delay_extension/delay_extension.c +++ b/neural_modelling/src/delay_extension/delay_extension.c @@ -444,10 +444,18 @@ static inline void spike_process(void) { spin1_mode_restore(state); } +//! \brief User event callback. +//! \details Delegates to spike_process() +//! \param[in] unused0: unused +//! \param[in] unused1: unused static void user_callback(UNUSED uint unused0, UNUSED uint unused1) { spike_process(); } +//! \brief Background event callback. +//! \details Handles sending delayed spikes at the right time. +//! \param[in] local_time: current simulation time +//! \param[in] timer_count: unused static void background_callback(uint local_time, UNUSED uint timer_count) { // reset the TDMA for this next cycle. tdma_processing_reset_phase(); @@ -479,14 +487,14 @@ static void background_callback(uint local_time, UNUSED uint timer_count) { uint32_t neuron_index = ((d * num_neurons) + n); uint32_t spike_key = neuron_index + key; - #if LOG_LEVEL >= LOG_DEBUG +#if LOG_LEVEL >= LOG_DEBUG if (delay_stage_spike_counters[n] > 0) { log_debug("Neuron %u sending %u spikes after delay" "stage %u with key %x", n, delay_stage_spike_counters[n], d, spike_key); } - #endif +#endif // fire n spikes as payload, 1 as none payload. if (has_key) { diff --git a/neural_modelling/src/neuron/c_main_synapses.c b/neural_modelling/src/neuron/c_main_synapses.c index 19e859a036e..78251f38532 100644 --- a/neural_modelling/src/neuron/c_main_synapses.c +++ b/neural_modelling/src/neuron/c_main_synapses.c @@ -128,6 +128,9 @@ void resume_callback(void) { synapses_resume(time + 1); } +//! \brief Timer event callback. +//! \param[in] unused0: unused +//! \param[in] unused1: unused void timer_callback(UNUSED uint unused0, UNUSED uint unused1) { time++; if (simulation_is_finished()) { diff --git a/neural_modelling/src/neuron/implementations/neuron_impl.h b/neural_modelling/src/neuron/implementations/neuron_impl.h index 11548581979..3bf244c61c2 100644 --- a/neural_modelling/src/neuron/implementations/neuron_impl.h +++ b/neural_modelling/src/neuron/implementations/neuron_impl.h @@ -46,9 +46,9 @@ static void neuron_impl_load_neuron_parameters( address_t address, uint32_t next, uint32_t n_neurons); //! \brief Do the timestep update for the particular implementation -//! \param[in] neuron_index: The index of the neuron to update +//! \param[in] timer_count: The timer count, used for TDMA packet spreading //! \param[in] time: The time step of the update -//! \param[in] external_bias: External input to be applied to the neuron +//! \param[in] n_neurons: The number of neurons static void neuron_impl_do_timestep_update( uint32_t timer_count, uint32_t time, uint32_t n_neurons); diff --git a/neural_modelling/src/neuron/implementations/neuron_impl_external_devices.h b/neural_modelling/src/neuron/implementations/neuron_impl_external_devices.h index ae39afcd41f..f89511555a2 100644 --- a/neural_modelling/src/neuron/implementations/neuron_impl_external_devices.h +++ b/neural_modelling/src/neuron/implementations/neuron_impl_external_devices.h @@ -330,9 +330,9 @@ static bool _test_will_fire(packet_firing_data_t *packet_firing) { SOMETIMES_UNUSED // Marked unused as only used sometimes //! \brief Do the timestep update for the particular implementation -//! \param[in] neuron_index: The index of the neuron to update +//! \param[in] timer_count: The timer count, used for TDMA packet spreading //! \param[in] time: The time step of the update -//! \param[in] external_bias: External input to be applied to the neuron +//! \param[in] n_neurons: The number of neurons static void neuron_impl_do_timestep_update( uint32_t timer_count, UNUSED uint32_t time, uint32_t n_neurons) { diff --git a/neural_modelling/src/neuron/implementations/neuron_impl_standard.h b/neural_modelling/src/neuron/implementations/neuron_impl_standard.h index 5ed625694a7..adb4c019744 100644 --- a/neural_modelling/src/neuron/implementations/neuron_impl_standard.h +++ b/neural_modelling/src/neuron/implementations/neuron_impl_standard.h @@ -245,6 +245,10 @@ static void neuron_impl_load_neuron_parameters( } SOMETIMES_UNUSED // Marked unused as only used sometimes +//! \brief Do the timestep update for the particular implementation +//! \param[in] timer_count: The timer count, used for TDMA packet spreading +//! \param[in] time: The time step of the update +//! \param[in] n_neurons: The number of neurons static void neuron_impl_do_timestep_update( uint32_t timer_count, uint32_t time, uint32_t n_neurons) { diff --git a/neural_modelling/src/neuron/models/neuron_model_izh_impl.h b/neural_modelling/src/neuron/models/neuron_model_izh_impl.h index 2a840d96231..c5f42142f90 100644 --- a/neural_modelling/src/neuron/models/neuron_model_izh_impl.h +++ b/neural_modelling/src/neuron/models/neuron_model_izh_impl.h @@ -112,11 +112,25 @@ static inline void rk2_kernel_midpoint( neuron->U += a * h * (-lastU1 - beta + b * eta); } - +//! \brief primary function called in timer loop after synaptic updates +//! \param[in] num_excitatory_inputs: Number of excitatory receptor types. +//! \param[in] exc_input: Pointer to array of inputs per receptor type received +//! this timer tick that produce a positive reaction within the neuron in +//! terms of stimulation. +//! \param[in] num_inhibitory_inputs: Number of inhibitory receptor types. +//! \param[in] inh_input: Pointer to array of inputs per receptor type received +//! this timer tick that produce a negative reaction within the neuron in +//! terms of stimulation. +//! \param[in] external_bias: This is the intrinsic plasticity which could be +//! used for ac, noisy input etc etc. (general purpose input) +//! \param[in,out] neuron: the pointer to a neuron parameter struct which +//! contains all the parameters for a specific neuron +//! \return the value to be compared with a threshold value to determine if the +//! neuron has spiked static state_t neuron_model_state_update( uint16_t num_excitatory_inputs, const input_t *exc_input, - uint16_t num_inhibitory_inputs, const input_t *inh_input, - input_t external_bias, neuron_t *restrict neuron) { + uint16_t num_inhibitory_inputs, const input_t *inh_input, + input_t external_bias, neuron_t *restrict neuron) { REAL total_exc = 0; REAL total_inh = 0; @@ -137,6 +151,9 @@ static state_t neuron_model_state_update( return neuron->V; } +//! \brief Indicates that the neuron has spiked +//! \param[in, out] neuron pointer to a neuron parameter struct which contains +//! all the parameters for a specific neuron static void neuron_model_has_spiked(neuron_t *restrict neuron) { // reset membrane voltage neuron->V = neuron->C; @@ -148,6 +165,11 @@ static void neuron_model_has_spiked(neuron_t *restrict neuron) { neuron->this_h = global_params->machine_timestep_ms * SIMPLE_TQ_OFFSET; } +//! \brief get the neuron membrane voltage for a given neuron parameter set +//! \param[in] neuron: a pointer to a neuron parameter struct which contains +//! all the parameters for a specific neuron +//! \return the membrane voltage for a given neuron with the neuron +//! parameters specified in neuron static state_t neuron_model_get_membrane_voltage(const neuron_t *neuron) { return neuron->V; } diff --git a/neural_modelling/src/neuron/models/neuron_model_lif_impl.h b/neural_modelling/src/neuron/models/neuron_model_lif_impl.h index b3145c47015..6c5cc03b4ba 100644 --- a/neural_modelling/src/neuron/models/neuron_model_lif_impl.h +++ b/neural_modelling/src/neuron/models/neuron_model_lif_impl.h @@ -68,6 +68,21 @@ static inline void lif_neuron_closed_form( neuron->V_membrane = alpha - (neuron->exp_TC * (alpha - V_prev)); } +//! \brief primary function called in timer loop after synaptic updates +//! \param[in] num_excitatory_inputs: Number of excitatory receptor types. +//! \param[in] exc_input: Pointer to array of inputs per receptor type received +//! this timer tick that produce a positive reaction within the neuron in +//! terms of stimulation. +//! \param[in] num_inhibitory_inputs: Number of inhibitory receptor types. +//! \param[in] inh_input: Pointer to array of inputs per receptor type received +//! this timer tick that produce a negative reaction within the neuron in +//! terms of stimulation. +//! \param[in] external_bias: This is the intrinsic plasticity which could be +//! used for ac, noisy input etc etc. (general purpose input) +//! \param[in,out] neuron: the pointer to a neuron parameter struct which +//! contains all the parameters for a specific neuron +//! \return the value to be compared with a threshold value to determine if the +//! neuron has spiked static state_t neuron_model_state_update( uint16_t num_excitatory_inputs, const input_t *exc_input, uint16_t num_inhibitory_inputs, const input_t *inh_input, @@ -97,6 +112,9 @@ static state_t neuron_model_state_update( return neuron->V_membrane; } +//! \brief Indicates that the neuron has spiked +//! \param[in, out] neuron pointer to a neuron parameter struct which contains +//! all the parameters for a specific neuron static void neuron_model_has_spiked(neuron_t *restrict neuron) { // reset membrane voltage neuron->V_membrane = neuron->V_reset; @@ -105,6 +123,11 @@ static void neuron_model_has_spiked(neuron_t *restrict neuron) { neuron->refract_timer = neuron->T_refract; } +//! \brief get the neuron membrane voltage for a given neuron parameter set +//! \param[in] neuron: a pointer to a neuron parameter struct which contains +//! all the parameters for a specific neuron +//! \return the membrane voltage for a given neuron with the neuron +//! parameters specified in neuron static state_t neuron_model_get_membrane_voltage(const neuron_t *neuron) { return neuron->V_membrane; } diff --git a/neural_modelling/src/neuron/neuron.c b/neural_modelling/src/neuron/neuron.c index faf75d9df5d..df43f1bb727 100644 --- a/neural_modelling/src/neuron/neuron.c +++ b/neural_modelling/src/neuron/neuron.c @@ -65,9 +65,7 @@ struct neuron_parameters { }; //! \brief does the memory copy for the neuron parameters -//! \param[in] address: the address where the neuron parameters are stored -//! in SDRAM -//! \return bool which is true if the mem copy's worked, false otherwise +//! \return true if the memory copies worked, false otherwise static bool neuron_load_neuron_parameters(void) { log_debug("loading parameters"); // call the neuron implementation functions to do the work diff --git a/neural_modelling/src/neuron/population_table/population_table.h b/neural_modelling/src/neuron/population_table/population_table.h index 950a1d568f6..94f5eab1881 100644 --- a/neural_modelling/src/neuron/population_table/population_table.h +++ b/neural_modelling/src/neuron/population_table/population_table.h @@ -70,6 +70,7 @@ bool population_table_get_first_address( size_t* n_bytes_to_transfer); //! \brief Determine if there are more items with the same key +//! \return Whether there are more items static inline bool population_table_is_next(void) { return items_to_go > 0; } diff --git a/neural_modelling/src/neuron/population_table/population_table_binary_search_impl.c b/neural_modelling/src/neuron/population_table/population_table_binary_search_impl.c index 33f36621e82..c0433253111 100644 --- a/neural_modelling/src/neuron/population_table/population_table_binary_search_impl.c +++ b/neural_modelling/src/neuron/population_table/population_table_binary_search_impl.c @@ -84,8 +84,8 @@ typedef union { extra_info extra; } address_list_entry; -// An Invalid address and row length; used to keep indices aligned between -// delayed and undelayed tables +//! \brief An Invalid address and row length +//! \details Used to keep indices aligned between delayed and undelayed tables #define INVALID_ADDRESS ((1 << N_ADDRESS_BITS) - 1) //! \brief The memory layout in SDRAM of the first part of the population table @@ -213,9 +213,9 @@ static inline uint32_t get_neuron_id( } //! \brief Get the neuron id of the neuron on the source core, for a spike with -// extra info +//! extra info //! \param[in] entry: the table entry -//! \param[in] extra_info: the extra info entry +//! \param[in] extra: the extra info entry //! \param[in] spike: the spike received //! \return the source neuron id local to the core static inline uint32_t get_local_neuron_id( diff --git a/neural_modelling/src/neuron/spike_processing.c b/neural_modelling/src/neuron/spike_processing.c index 3fb6ea9b164..fcc5057a872 100644 --- a/neural_modelling/src/neuron/spike_processing.c +++ b/neural_modelling/src/neuron/spike_processing.c @@ -425,7 +425,6 @@ void user_event_callback(UNUSED uint unused0, UNUSED uint unused1) { } /* INTERFACE FUNCTIONS - cannot be static */ -//! \brief clears the input buffer of packets and records them void spike_processing_clear_input_buffer(timer_t time) { uint32_t n_spikes = in_spikes_size(); if (clear_input_buffers_of_late_packets) { @@ -491,8 +490,6 @@ void spike_processing_store_provenance(struct spike_processing_provenance *prov) prov->max_filled_input_buffer_size = biggest_fill_size_of_input_buffer; } -//! \brief set the number of times spike_processing has to attempt rewiring -//! \return currently, always true bool spike_processing_do_rewiring(int number_of_rewires) { // disable interrupts uint cpsr = spin1_int_disable(); diff --git a/neural_modelling/src/neuron/spike_processing.h b/neural_modelling/src/neuron/spike_processing.h index ff5a12c14c2..c394a34c0f0 100644 --- a/neural_modelling/src/neuron/spike_processing.h +++ b/neural_modelling/src/neuron/spike_processing.h @@ -24,7 +24,7 @@ #include #include -// Provenance for spike processing +//! Provenance for spike processing struct spike_processing_provenance { //! A count of the times that the synaptic input circular buffers overflowed uint32_t n_input_buffer_overflows; @@ -46,9 +46,8 @@ struct spike_processing_provenance { //! Multicast packet receive interrupt priority //! \param[in] user_event_priority: User event interrupt priority //! \param[in] incoming_spike_buffer_size: Size of buffer for receiving spikes -//! \param[in] clear_input_buffers_of_late_packets: Whether packets that are left -//! at the end of a time step are -//! wiped +//! \param[in] clear_input_buffers_of_late_packets_init: +//! Whether packets that are left at the end of a time step are wiped //! \param[in] packets_per_timestep_region: //! The recording region to use for the packets per timestep //! \return True if initialisation succeeded diff --git a/neural_modelling/src/neuron/spike_processing_fast.h b/neural_modelling/src/neuron/spike_processing_fast.h index e1468bb106c..9375752d7fe 100644 --- a/neural_modelling/src/neuron/spike_processing_fast.h +++ b/neural_modelling/src/neuron/spike_processing_fast.h @@ -48,7 +48,7 @@ struct key_config { uint32_t self_connected; }; -// Provenance for spike processing +//! Provenance for spike processing struct spike_processing_fast_provenance { //! A count of the times that the synaptic input circular buffers overflowed uint32_t n_input_buffer_overflows; @@ -72,7 +72,6 @@ struct spike_processing_fast_provenance { uint32_t n_skipped_time_steps; //! The maximum additional time taken to transfer uint32_t max_transfer_timer_overrun; - }; //! \brief Set up spike processing diff --git a/neural_modelling/src/neuron/structural_plasticity/synaptogenesis/sp_structs.h b/neural_modelling/src/neuron/structural_plasticity/synaptogenesis/sp_structs.h index 275cc33c8f3..3abe83fb749 100644 --- a/neural_modelling/src/neuron/structural_plasticity/synaptogenesis/sp_structs.h +++ b/neural_modelling/src/neuron/structural_plasticity/synaptogenesis/sp_structs.h @@ -233,7 +233,6 @@ static inline bool sp_structs_add_synapse( //! \brief Common code for structural plasticity initialisation. //! \param[in] sdram_sp_address: Address of the configuration region. -//! \param[in] n_neurons: The number of neurons on this core. //! \param[in,out] rewiring_data: //! Address of the rewiring information structure to fill out. //! \param[in,out] pre_info: diff --git a/neural_modelling/src/neuron/structural_plasticity/synaptogenesis/topographic_map_impl.c b/neural_modelling/src/neuron/structural_plasticity/synaptogenesis/topographic_map_impl.c index a5a9b30bb52..85880836655 100644 --- a/neural_modelling/src/neuron/structural_plasticity/synaptogenesis/topographic_map_impl.c +++ b/neural_modelling/src/neuron/structural_plasticity/synaptogenesis/topographic_map_impl.c @@ -43,10 +43,16 @@ #include "elimination/elimination.h" #include "formation/formation.h" -// define values used in recording -#define ELIM_FLAG 0 -#define FORM_FLAG 1 +//! values used in recording +enum { + //! Elimination flag + ELIM_FLAG = 0, + //! Formation flag + FORM_FLAG = 1 +}; +//! How much to shift post-IDs by #define ID_SHIFT 1 +//! How much to shift pre-IDs by #define PRE_ID_SHIFT 9 //----------------------------------------------------------------------------- @@ -88,9 +94,9 @@ typedef struct structural_recording_values_t { uint32_t value; } structural_recording_values_t; +//! Working buffer for the recording of structural changes structural_recording_values_t structural_recording_values; - //! Timer callbacks since last rewiring static uint32_t last_rewiring_time = 0; diff --git a/neural_modelling/src/neuron/structural_plasticity/synaptogenesis_dynamics.h b/neural_modelling/src/neuron/structural_plasticity/synaptogenesis_dynamics.h index ae1f1ca4762..9aa18f244c4 100644 --- a/neural_modelling/src/neuron/structural_plasticity/synaptogenesis_dynamics.h +++ b/neural_modelling/src/neuron/structural_plasticity/synaptogenesis_dynamics.h @@ -31,6 +31,8 @@ //! parameters (random seed, spread of receptive field etc.) //! \param[in] sdram_sp_address: Address of the start of the SDRAM region //! which contains synaptic rewiring params. +//! \param[in,out] recording_regions_used: +//! Variable used to track what recording regions have been used //! \return Whether we were successful. bool synaptogenesis_dynamics_initialise( address_t sdram_sp_address, uint32_t *recording_regions_used); diff --git a/neural_modelling/src/neuron/synapse_row.h b/neural_modelling/src/neuron/synapse_row.h index 0a627dd65f7..49106f044ad 100644 --- a/neural_modelling/src/neuron/synapse_row.h +++ b/neural_modelling/src/neuron/synapse_row.h @@ -218,6 +218,7 @@ static inline index_t synapse_row_sparse_type_index( //! \param[in] x: The value to decode //! \param[in] synapse_type_index_bits: //! Number of bits for the synapse type and index (depends on type) +//! \param[in] synapse_delay_mask: The mask for selecting the bits of the delay //! \return the delay static inline index_t synapse_row_sparse_delay( uint32_t x, uint32_t synapse_type_index_bits, uint32_t synapse_delay_mask) { @@ -249,11 +250,12 @@ static inline input_t synapse_row_convert_weight_to_input( //! \brief Get the index of the ring buffer for a given timestep, synapse type //! and neuron index -//! \param[in] simulation_timestep: -//! \param[in] synapse_type_index: -//! \param[in] neuron_index: -//! \param[in] synapse_type_index_bits: -//! \param[in] synapse_index_bits: +//! \param[in] simulation_timestep: The timestep +//! \param[in] synapse_type_index: The synapse type index +//! \param[in] neuron_index: The neuron index +//! \param[in] synapse_type_index_bits: Number of bits for type and index +//! \param[in] synapse_index_bits: Number of bits for index +//! \param[in] synapse_delay_mask: Mask for delay //! \return Index into the ring buffer static inline index_t synapse_row_get_ring_buffer_index( uint32_t simulation_timestep, uint32_t synapse_type_index, @@ -266,9 +268,9 @@ static inline index_t synapse_row_get_ring_buffer_index( //! \brief Get the index of the ring buffer for time 0, synapse type //! and neuron index -//! \param[in] synapse_type_index: -//! \param[in] neuron_index: -//! \param[in] synapse_index_bits: +//! \param[in] synapse_type_index: The synapse type index +//! \param[in] neuron_index: The neuron index +//! \param[in] synapse_index_bits: Number of bits for index //! \return Index into the ring buffer static inline index_t synapse_row_get_ring_buffer_index_time_0( uint32_t synapse_type_index, uint32_t neuron_index, @@ -277,8 +279,9 @@ static inline index_t synapse_row_get_ring_buffer_index_time_0( } //! \brief Get the index of the first ring buffer for a given timestep -//! \param[in] simulation_timestep: -//! \param[in] synapse_type_index_bits: +//! \param[in] simulation_timestep: The timestep +//! \param[in] synapse_type_index_bits: Number of bits for type and index +//! \param[in] synapse_delay_mask: Mask for delay //! \return Index into the ring buffer static inline index_t synapse_row_get_first_ring_buffer_index( uint32_t simulation_timestep, uint32_t synapse_type_index_bits, @@ -288,9 +291,10 @@ static inline index_t synapse_row_get_first_ring_buffer_index( //! \brief Get the index of the ring buffer for a given timestep and combined //! synapse type and neuron index (as stored in a synapse row) -//! \param[in] simulation_timestep: +//! \param[in] simulation_timestep: The timestep //! \param[in] combined_synapse_neuron_index: -//! \param[in] synapse_type_index_bits: +//! \param[in] synapse_type_index_bits: Number of bits for type and index +//! \param[in] synapse_delay_mask: Mask for delay //! \return Index into the ring buffer static inline index_t synapse_row_get_ring_buffer_index_combined( uint32_t simulation_timestep, diff --git a/neural_modelling/src/neuron/synapse_types/synapse_types.h b/neural_modelling/src/neuron/synapse_types/synapse_types.h index 6ab49058f33..08055523783 100644 --- a/neural_modelling/src/neuron/synapse_types/synapse_types.h +++ b/neural_modelling/src/neuron/synapse_types/synapse_types.h @@ -54,6 +54,7 @@ static void synapse_types_add_neuron_input( //! \brief extracts the excitatory input buffers from the buffers available //! for a given neuron ID +//! \param[in,out] excitatory_response: Buffer to put response in //! \param[in] parameters: the pointer to the parameters to use //! \return Pointer to array of excitatory input buffers for a given neuron ID. static input_t* synapse_types_get_excitatory_input( @@ -61,15 +62,15 @@ static input_t* synapse_types_get_excitatory_input( //! \brief extracts the inhibitory input buffers from the buffers available //! for a given neuron ID +//! \param[in,out] inhibitory_response: Buffer to put response in //! \param[in] parameters: the pointer to the parameters to use //! \return Pointer to array of inhibitory input buffers for a given neuron ID. static input_t* synapse_types_get_inhibitory_input( input_t *inhibitory_response, synapse_param_t *parameters); //! \brief returns a human readable character for the type of synapse. -//! -//! Examples would be `X` = excitatory types, `I` = inhibitory types, etc. -//! +//! \details +//! Examples would be `X` = excitatory types, `I` = inhibitory types, etc. //! \param[in] synapse_type_index: the synapse type index //! (there is a specific index interpretation in each synapse type) //! \return a human readable character representing the synapse type. diff --git a/neural_modelling/src/neuron/synapse_types/synapse_types_alpha_impl.h b/neural_modelling/src/neuron/synapse_types/synapse_types_alpha_impl.h index 6486b5ed295..81151ad7742 100644 --- a/neural_modelling/src/neuron/synapse_types/synapse_types_alpha_impl.h +++ b/neural_modelling/src/neuron/synapse_types/synapse_types_alpha_impl.h @@ -140,6 +140,7 @@ static inline void synapse_types_add_neuron_input( //! \brief extracts the excitatory input buffers from the buffers available //! for a given neuron ID +//! \param[in,out] excitatory_response: Buffer to put response in //! \param[in] parameters: the pointer to the parameters to use //! \return Pointer to array of excitatory input buffers for a given neuron ID. static inline input_t* synapse_types_get_excitatory_input( @@ -151,6 +152,7 @@ static inline input_t* synapse_types_get_excitatory_input( //! \brief extracts the inhibitory input buffers from the buffers available //! for a given neuron ID +//! \param[in,out] inhibitory_response: Buffer to put response in //! \param[in] parameters: the pointer to the parameters to use //! \return Pointer to array of inhibitory input buffers for a given neuron ID. static inline input_t* synapse_types_get_inhibitory_input( diff --git a/neural_modelling/src/neuron/synapse_types/synapse_types_delta_impl.h b/neural_modelling/src/neuron/synapse_types/synapse_types_delta_impl.h index 1111c9e9793..25c118c0c30 100644 --- a/neural_modelling/src/neuron/synapse_types/synapse_types_delta_impl.h +++ b/neural_modelling/src/neuron/synapse_types/synapse_types_delta_impl.h @@ -124,6 +124,7 @@ static inline void synapse_types_add_neuron_input( //! \brief extracts the excitatory input buffers from the buffers available //! for a given parameter set +//! \param[in,out] excitatory_response: Buffer to put response in //! \param[in] parameters: the pointer to the parameters to use //! \return the excitatory input buffers for a given neuron ID. static inline input_t *synapse_types_get_excitatory_input( @@ -134,6 +135,7 @@ static inline input_t *synapse_types_get_excitatory_input( //! \brief extracts the inhibitory input buffers from the buffers available //! for a given parameter set +//! \param[in,out] inhibitory_response: Buffer to put response in //! \param[in] parameters: the pointer to the parameters to use //! \return the inhibitory input buffers for a given neuron ID. static inline input_t *synapse_types_get_inhibitory_input( diff --git a/neural_modelling/src/neuron/synapse_types/synapse_types_dual_excitatory_exponential_impl.h b/neural_modelling/src/neuron/synapse_types/synapse_types_dual_excitatory_exponential_impl.h index 5160c867a53..f9513eb1899 100644 --- a/neural_modelling/src/neuron/synapse_types/synapse_types_dual_excitatory_exponential_impl.h +++ b/neural_modelling/src/neuron/synapse_types/synapse_types_dual_excitatory_exponential_impl.h @@ -129,6 +129,7 @@ static inline void synapse_types_add_neuron_input( //! \brief extracts the excitatory input buffers from the buffers available //! for a given parameter set +//! \param[in,out] excitatory_response: Buffer to put response in //! \param[in] parameters: the pointer to the parameters to use //! \return the excitatory input buffers for a given neuron ID. static inline input_t* synapse_types_get_excitatory_input( @@ -140,6 +141,7 @@ static inline input_t* synapse_types_get_excitatory_input( //! \brief extracts the inhibitory input buffers from the buffers available //! for a given parameter set +//! \param[in,out] inhibitory_response: Buffer to put response in //! \param[in] parameters: the pointer to the parameters to use //! \return the inhibitory input buffers for a given neuron ID. static inline input_t* synapse_types_get_inhibitory_input( diff --git a/neural_modelling/src/neuron/synapse_types/synapse_types_exponential_impl.h b/neural_modelling/src/neuron/synapse_types/synapse_types_exponential_impl.h index 6b6f557f09b..7d663d7dcf9 100644 --- a/neural_modelling/src/neuron/synapse_types/synapse_types_exponential_impl.h +++ b/neural_modelling/src/neuron/synapse_types/synapse_types_exponential_impl.h @@ -124,6 +124,7 @@ static inline void synapse_types_add_neuron_input( //! \brief extracts the excitatory input buffers from the buffers available //! for a given parameter set +//! \param[in,out] excitatory_response: Buffer to put response in //! \param[in] parameters: the pointer to the parameters to use //! \return the excitatory input buffers for a given neuron ID. static inline input_t* synapse_types_get_excitatory_input( @@ -134,6 +135,7 @@ static inline input_t* synapse_types_get_excitatory_input( //! \brief extracts the inhibitory input buffers from the buffers available //! for a given parameter set +//! \param[in,out] inhibitory_response: Buffer to put response in //! \param[in] parameters: the pointer to the parameters to use //! \return the inhibitory input buffers for a given neuron ID. static inline input_t* synapse_types_get_inhibitory_input( diff --git a/neural_modelling/src/neuron/synapse_types/synapse_types_semd_impl.h b/neural_modelling/src/neuron/synapse_types/synapse_types_semd_impl.h index 1360aab1445..afc5305d101 100644 --- a/neural_modelling/src/neuron/synapse_types/synapse_types_semd_impl.h +++ b/neural_modelling/src/neuron/synapse_types/synapse_types_semd_impl.h @@ -131,6 +131,7 @@ static inline void synapse_types_add_neuron_input( //! \brief extracts the excitatory input buffers from the buffers available //! for a given parameter set +//! \param[in,out] excitatory_response: Buffer to put response in //! \param[in] parameters: the pointer to the parameters to use //! \return the excitatory input buffers for a given neuron ID. static inline input_t *synapse_types_get_excitatory_input( @@ -154,6 +155,7 @@ static inline input_t *synapse_types_get_excitatory_input( //! \brief extracts the inhibitory input buffers from the buffers available //! for a given parameter set +//! \param[in,out] inhibitory_response: Buffer to put response in //! \param[in] parameters: the pointer to the parameters to use //! \return the inhibitory input buffers for a given neuron ID. static inline input_t *synapse_types_get_inhibitory_input( diff --git a/neural_modelling/src/neuron/synapses.c b/neural_modelling/src/neuron/synapses.c index c8d1a5840d6..5eff714fe66 100644 --- a/neural_modelling/src/neuron/synapses.c +++ b/neural_modelling/src/neuron/synapses.c @@ -80,6 +80,7 @@ uint32_t synapse_delay_mask; //! Count of the number of times the ring buffers have saturated uint32_t synapses_saturation_count = 0; +//! Number of neurons static uint32_t n_neurons_peak; @@ -188,6 +189,7 @@ static inline void print_ring_buffers(uint32_t time) { //! be put into the ring buffer. //! \param[in] fixed_region: The fixed region of the synaptic matrix //! \param[in] time: The current simulation time +//! \return Always true static inline bool process_fixed_synapses( synapse_row_fixed_part_t *fixed_region, uint32_t time) { uint32_t *synaptic_words = synapse_row_fixed_weight_controls(fixed_region); @@ -380,7 +382,7 @@ uint32_t synapses_get_pre_synaptic_events(void) { synapse_dynamics_get_plastic_pre_synaptic_events()); } -void synapses_resume(uint32_t time) { +void synapses_resume(timer_t time) { // If the time has been reset to zero then the ring buffers need to be // flushed in case there is a delayed spike left over from a previous run if (time == 0) { diff --git a/neural_modelling/src/neuron/synapses.h b/neural_modelling/src/neuron/synapses.h index 06b399068b7..5408c583e66 100644 --- a/neural_modelling/src/neuron/synapses.h +++ b/neural_modelling/src/neuron/synapses.h @@ -74,7 +74,7 @@ static inline void synapses_print_weight( //! \param[out] ring_buffer_to_input_buffer_left_shifts: //! Array of shifts to use when converting from ring buffer values to input //! buffer values -//! \param[out] clear_input_buffers_of_late_packets: +//! \param[out] clear_input_buffers_of_late_packets_init: //! Inicates whether to clear the input buffers each time step //! \param[out] incoming_spike_buffer_size: //! The number of spikes to support in the incoming spike circular buffer diff --git a/neural_modelling/src/synapse_expander/delay_expander.c b/neural_modelling/src/synapse_expander/delay_expander.c index 1b26748086f..81eb8901d38 100644 --- a/neural_modelling/src/synapse_expander/delay_expander.c +++ b/neural_modelling/src/synapse_expander/delay_expander.c @@ -47,15 +47,15 @@ struct delay_builder_config { /** * \brief Generate the data for a single connector - * \param[in,out] in_region: The address to read the parameters from. Should be - * updated to the position just after the parameters - * after calling. - * \param[in,out] neuron_delay_stage_config: Bit fields into which to write the - * delay information - * \param[in] post_slice_start: The start of the slice of the delay extension to - * generate for - * \param[in] post_slice_count: The number of neurons of the delay extension to - * generate for + * \param[in,out] in_region: + * The address to read the parameters from. Should be updated to the + * position just after the parameters after calling. + * \param[in,out] neuron_delay_stage_config: + * Bit fields into which to write the delay information + * \param[in] pre_slice_start: + * The start of the slice of the delay extension to generate for + * \param[in] pre_slice_count: + * The number of neurons of the delay extension to generate for * \return True if the region was correctly generated, False if there was an * error */ From f59c23dda8a5dff833afe3155e8b19235a610910 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Tue, 5 Oct 2021 13:36:43 +0100 Subject: [PATCH 05/44] allow for mutliple send_sync --- .../test_external_devices/test_live_sync.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/spynnaker_integration_tests/test_external_devices/test_live_sync.py b/spynnaker_integration_tests/test_external_devices/test_live_sync.py index 68c708ad348..f736fc229ea 100644 --- a/spynnaker_integration_tests/test_external_devices/test_live_sync.py +++ b/spynnaker_integration_tests/test_external_devices/test_live_sync.py @@ -77,6 +77,10 @@ def test_live_sync(): sim_finished = True p.end() + # On slow connections send_sync is sent more often + n_spikes = [x for x in n_spikes if x > 0] + assert 5 == len(n_spikes) + # 20 spikes should be in each range, but some could get lost, so check # for a range for i in range(5): From d422d9545b279ef45985716a1f088daf0e19a543 Mon Sep 17 00:00:00 2001 From: Donal Fellows Date: Tue, 5 Oct 2021 14:05:39 +0100 Subject: [PATCH 06/44] Trying to fix a crash... --- .github/workflows/publish.yml | 2 +- neural_modelling/Doxyfile | 24 ++---------------------- 2 files changed, 3 insertions(+), 23 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index c9275fb0b63..82405815490 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -65,7 +65,7 @@ jobs: with: directory: doc/source - name: Build C documentation - uses: mattnotmitt/doxygen-action@v1.1.0 + uses: mattnotmitt/doxygen-action@v1.3.1 with: working-directory: neural_modelling diff --git a/neural_modelling/Doxyfile b/neural_modelling/Doxyfile index b7754e76cc0..ee8db3e81f0 100644 --- a/neural_modelling/Doxyfile +++ b/neural_modelling/Doxyfile @@ -245,26 +245,6 @@ ALIASES = OPTIMIZE_OUTPUT_FOR_C = YES -# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or -# Python sources only. Doxygen will then generate output that is more tailored -# for that language. For instance, namespaces will be presented as packages, -# qualified scopes will look different, etc. -# The default value is: NO. - -OPTIMIZE_OUTPUT_JAVA = NO - -# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran -# sources. Doxygen will then generate output that is tailored for Fortran. -# The default value is: NO. - -OPTIMIZE_FOR_FORTRAN = NO - -# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL -# sources. Doxygen will then generate output that is tailored for VHDL. -# The default value is: NO. - -OPTIMIZE_OUTPUT_VHDL = NO - # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given # extension. Doxygen has a built-in mapping, but you can override or extend it @@ -279,7 +259,7 @@ OPTIMIZE_OUTPUT_VHDL = NO # Note that for custom extensions you also need to set FILE_PATTERNS otherwise # the files are not read by doxygen. -EXTENSION_MAPPING = +EXTENSION_MAPPING = h=C # If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments # according to the Markdown format, which allows for more readable @@ -647,7 +627,7 @@ SHOW_FILES = YES # Folder Tree View (if specified). # The default value is: YES. -SHOW_NAMESPACES = YES +SHOW_NAMESPACES = NO # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from From 36a7f861be33ae62eec8cd8d9ffa6670c30d70b4 Mon Sep 17 00:00:00 2001 From: Garandel Date: Thu, 14 Oct 2021 15:24:52 +0000 Subject: [PATCH 07/44] modified: meanfield/models/meanfield_model_impl.c add the reel error function --- neural_modelling/src/meanfield/models/meanfield_model_impl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/neural_modelling/src/meanfield/models/meanfield_model_impl.c b/neural_modelling/src/meanfield/models/meanfield_model_impl.c index 332d406f008..cc6f4dcccbd 100644 --- a/neural_modelling/src/meanfield/models/meanfield_model_impl.c +++ b/neural_modelling/src/meanfield/models/meanfield_model_impl.c @@ -76,8 +76,8 @@ void error_function( REAL x, REAL factor, mathsbox_t *restrict mathsbox){ REAL Erfc = mathsbox->err_func; for(t=0; t==x; t+=dt){ //Erfc += dt; //test otherwise IDTM overload - //Erfc += factor*(2/sqrtk(Pi))*expk(-(t*t)); // the real one - Erfc += factor+t*t;//fake one + Erfc += factor*(2/sqrtk(Pi))*expk(-(t*t)); // the real one + //Erfc += factor+t*t;//fake one } mathsbox->err_func = Erfc; From 2fa237fe604e5c9fba33ad40bbfb99598072a5a8 Mon Sep 17 00:00:00 2001 From: Garandel Date: Thu, 14 Oct 2021 15:43:15 +0000 Subject: [PATCH 08/44] modified: meanfield/models/meanfield_model_impl.c change real error function for an erzate --- neural_modelling/src/meanfield/models/meanfield_model_impl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/neural_modelling/src/meanfield/models/meanfield_model_impl.c b/neural_modelling/src/meanfield/models/meanfield_model_impl.c index cc6f4dcccbd..c96c8844817 100644 --- a/neural_modelling/src/meanfield/models/meanfield_model_impl.c +++ b/neural_modelling/src/meanfield/models/meanfield_model_impl.c @@ -76,7 +76,8 @@ void error_function( REAL x, REAL factor, mathsbox_t *restrict mathsbox){ REAL Erfc = mathsbox->err_func; for(t=0; t==x; t+=dt){ //Erfc += dt; //test otherwise IDTM overload - Erfc += factor*(2/sqrtk(Pi))*expk(-(t*t)); // the real one + //Erfc += factor*(2/sqrtk(Pi))*expk(-(t*t)); // the real one + Erfc += factor*expk(-(t*t)); //Erfc += factor+t*t;//fake one } From d21e70129d284c5ac6fbe881578455cdd974086b Mon Sep 17 00:00:00 2001 From: Garandel Date: Thu, 14 Oct 2021 15:57:19 +0000 Subject: [PATCH 09/44] modified: meanfield/models/meanfield_model_impl.c write some comments --- .../src/meanfield/models/meanfield_model_impl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/neural_modelling/src/meanfield/models/meanfield_model_impl.c b/neural_modelling/src/meanfield/models/meanfield_model_impl.c index c96c8844817..ba7a001294e 100644 --- a/neural_modelling/src/meanfield/models/meanfield_model_impl.c +++ b/neural_modelling/src/meanfield/models/meanfield_model_impl.c @@ -75,9 +75,9 @@ void error_function( REAL x, REAL factor, mathsbox_t *restrict mathsbox){ REAL Pi = 3.1415927k; REAL Erfc = mathsbox->err_func; for(t=0; t==x; t+=dt){ - //Erfc += dt; //test otherwise IDTM overload - //Erfc += factor*(2/sqrtk(Pi))*expk(-(t*t)); // the real one - Erfc += factor*expk(-(t*t)); + //Erfc += dt; //test otherwise ITCM overload + //Erfc += factor*(2/sqrtk(Pi))*expk(-(t*t)); // the real one overflowed ITCM + Erfc += factor*expk(-(t*t)); //working like this one //Erfc += factor+t*t;//fake one } From 14f0c87409a77d93dddbceb7f819ece87822d879 Mon Sep 17 00:00:00 2001 From: Garandel Date: Fri, 15 Oct 2021 09:19:50 +0000 Subject: [PATCH 10/44] modified: meanfield/models/meanfield_model_impl.c Do an approxiamtion of 2 over sqrt(pi) in order to remove the error due to the sqrtk() function. Start to remove division in the threshold_func(). --- .../meanfield/models/meanfield_model_impl.c | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/neural_modelling/src/meanfield/models/meanfield_model_impl.c b/neural_modelling/src/meanfield/models/meanfield_model_impl.c index ba7a001294e..2e0cc400d73 100644 --- a/neural_modelling/src/meanfield/models/meanfield_model_impl.c +++ b/neural_modelling/src/meanfield/models/meanfield_model_impl.c @@ -72,13 +72,14 @@ void error_function( REAL x, REAL factor, mathsbox_t *restrict mathsbox){ REAL dt = x/mathsbox->error_func_sample; REAL t; - REAL Pi = 3.1415927k; + //REAL Pi = 3.1415927;// here was a k + REAL two_over_sqrt_Pi = 1.128379167; //APPROXIMATION REAL Erfc = mathsbox->err_func; for(t=0; t==x; t+=dt){ //Erfc += dt; //test otherwise ITCM overload //Erfc += factor*(2/sqrtk(Pi))*expk(-(t*t)); // the real one overflowed ITCM - Erfc += factor*expk(-(t*t)); //working like this one - //Erfc += factor+t*t;//fake one + Erfc += factor*two_over_sqrt_Pi*expk(-(t*t)); //working like this one + //Erfc += factor+t*t;//fake one working } mathsbox->err_func = Erfc; @@ -117,7 +118,7 @@ void threshold_func(config_t *restrict config) */ // + 0.\ //P4*np.log(muGn) - /* + config->Vthre = config->P0\ + config->P1*(config->muV-config->muV0)/config->DmuV0\ + config->P2*(config->sV-config->sV0)/config->DsV0\ @@ -128,18 +129,13 @@ void threshold_func(config_t *restrict config) + config->P8*(config->muV-config->muV0)/config->DmuV0*(config->sV-config->sV0)/config->DsV0\ + config->P9*(config->muV-config->muV0)/config->DmuV0*(config->TvN-config->TvN0)/config->DTvN0\ + config->P10*(config->sV-config->sV0)/config->DsV0*(config->TvN-config->TvN0)/config->DTvN0; - */ - - config->Vthre = config->P0; - //return config->Vthre; + //config->Vthre = config->P0; } /* - REAL ONE get_fluct_regime_varsup -*/ -/* +// REAL ONE get_fluct_regime_varsup void get_fluct_regime_varsup(REAL Ve, REAL Vi, config_t *restrict params) { //takes 880 bytes overflowed ITCM @@ -198,6 +194,7 @@ void get_fluct_regime_varsup(REAL Ve, REAL Vi, config_t *restrict params) //return params->muV;//, sV+1e-12, muGn, TvN } +//END of the REAL get_fluct_regime_varsup */ @@ -262,7 +259,7 @@ void get_fluct_regime_varsup(REAL Ve, REAL Vi, config_t *restrict params) //return params->muV;//, sV+1e-12, muGn, TvN } -//END of the get_fluct_regime_varsup FAKE +//END of the FAKE get_fluct_regime_varsup From ded939e56ff4173f181700a265145c85c7f5466a Mon Sep 17 00:00:00 2001 From: Garandel Date: Fri, 15 Oct 2021 12:20:18 +0000 Subject: [PATCH 11/44] remove config-> in the thre_func in order to make a code more clear --- .../meanfield/models/meanfield_model_impl.c | 68 +++++++++++-------- 1 file changed, 41 insertions(+), 27 deletions(-) diff --git a/neural_modelling/src/meanfield/models/meanfield_model_impl.c b/neural_modelling/src/meanfield/models/meanfield_model_impl.c index 2e0cc400d73..462b3ffbddb 100644 --- a/neural_modelling/src/meanfield/models/meanfield_model_impl.c +++ b/neural_modelling/src/meanfield/models/meanfield_model_impl.c @@ -99,36 +99,50 @@ void threshold_func(config_t *restrict config) /*NEED TO AVOID DIVISION AS POSSIBLE but not for now */ - /* - config->muV0=-0.06; - config->DmuV0=0.01; - - config->sV0=0.004; - config->DsV0=0.006; - - config->TvN0=0.5; - config->DTvN0=1.; - - config->muV=0.; - config->sV=0.; - config->muGn=0.; - config->TvN=0.; - config->Vthre=0.; - config->Fout_th=0.; - */ + + muV0 = config->muV0;//=-0.06; + DmuV0 = config->DmuV0;//=0.01; + + sV0 = config->sV0;//=0.004; + DsV0 = config->DsV0;//=0.006; + + TvN0 = config->TvN0;//=0.5; + DTvN0 = config->DTvN0;//=1.; + + muV = config->muV;//=0.; + sV = config->sV;//=0.; + muGn = config->muGn;//=0.; + TvN = config->TvN;//=0.; + Vthre = config->Vthre;//=0.; + Fout_th = config->Fout_th;//=0.; + + P0 = config->P0; + P1 = config->P1; + P2 = config->P2; + P3 = config->P3; + P4 = config->P4; + P5 = config->P5; + P6 = config->P6; + P7 = config->P7; + P8 = config->P8; + P9 = config->P9; + P10 = config->P10; + + + // + 0.\ //P4*np.log(muGn) - config->Vthre = config->P0\ - + config->P1*(config->muV-config->muV0)/config->DmuV0\ - + config->P2*(config->sV-config->sV0)/config->DsV0\ - + config->P3*(config->TvN-config->TvN0)/config->DTvN0\ - + config->P5*((config->muV-config->muV0)/config->DmuV0)*((config->muV-config->muV0)/config->DmuV0)\ - + config->P6*((config->sV-config->sV0)/config->DsV0)*((config->sV-config->sV0)/config->DsV0)\ - + config->P7*((config->TvN-config->TvN0)/config->DTvN0)*((config->TvN-config->TvN0)/config->DTvN0)\ - + config->P8*(config->muV-config->muV0)/config->DmuV0*(config->sV-config->sV0)/config->DsV0\ - + config->P9*(config->muV-config->muV0)/config->DmuV0*(config->TvN-config->TvN0)/config->DTvN0\ - + config->P10*(config->sV-config->sV0)/config->DsV0*(config->TvN-config->TvN0)/config->DTvN0; + Vthre = P0\ + + P1*(muV-muV0)/DmuV0\ + + P2*(sV-sV0)/DsV0\ + + P3*(TvN-TvN0)/DTvN0\ + + P5*((muV-muV0)/DmuV0)*((muV-muV0)/DmuV0)\ + + P6*((sV-sV0)/DsV0)*((sV-sV0)/DsV0)\ + + P7*((TvN-TvN0)/DTvN0)*((TvN-TvN0)/DTvN0)\ + + P8*(muV-muV0)/DmuV0*(sV-sV0)/DsV0\ + + P9*(muV-muV0)/DmuV0*(TvN-TvN0)/DTvN0\ + + P10*(sV-sV0)/DsV0*(TvN-TvN0)/DTvN0; //config->Vthre = config->P0; From 2d023c835b34e179891aab84487516b7772f8893 Mon Sep 17 00:00:00 2001 From: Garandel Date: Fri, 15 Oct 2021 13:55:14 +0000 Subject: [PATCH 12/44] modified: meanfield/models/meanfield_model_impl.c modified: meanfield/models/meanfield_model_impl.h Set threshold_func() add and remove r_squared() because don't implemented yet. No removing of division yet. --- .../meanfield/models/meanfield_model_impl.c | 54 +++++++++---------- .../meanfield/models/meanfield_model_impl.h | 1 + 2 files changed, 28 insertions(+), 27 deletions(-) diff --git a/neural_modelling/src/meanfield/models/meanfield_model_impl.c b/neural_modelling/src/meanfield/models/meanfield_model_impl.c index 462b3ffbddb..f036a503439 100644 --- a/neural_modelling/src/meanfield/models/meanfield_model_impl.c +++ b/neural_modelling/src/meanfield/models/meanfield_model_impl.c @@ -100,33 +100,33 @@ void threshold_func(config_t *restrict config) but not for now */ - muV0 = config->muV0;//=-0.06; - DmuV0 = config->DmuV0;//=0.01; + REAL muV0 = config->muV0;//=-0.06; + REAL DmuV0 = config->DmuV0;//=0.01; - sV0 = config->sV0;//=0.004; - DsV0 = config->DsV0;//=0.006; + REAL sV0 = config->sV0;//=0.004; + REAL DsV0 = config->DsV0;//=0.006; - TvN0 = config->TvN0;//=0.5; - DTvN0 = config->DTvN0;//=1.; + REAL TvN0 = config->TvN0;//=0.5; + REAL DTvN0 = config->DTvN0;//=1.; - muV = config->muV;//=0.; - sV = config->sV;//=0.; - muGn = config->muGn;//=0.; - TvN = config->TvN;//=0.; - Vthre = config->Vthre;//=0.; - Fout_th = config->Fout_th;//=0.; + REAL muV = config->muV;//=0.; + REAL sV = config->sV;//=0.; + //REAL muGn = config->muGn;//=0.; + REAL TvN = config->TvN;//=0.; + REAL Vthre = config->Vthre;//=0.; + //REAL Fout_th = config->Fout_th;//=0.; - P0 = config->P0; - P1 = config->P1; - P2 = config->P2; - P3 = config->P3; - P4 = config->P4; - P5 = config->P5; - P6 = config->P6; - P7 = config->P7; - P8 = config->P8; - P9 = config->P9; - P10 = config->P10; + REAL P0 = config->P0; + REAL P1 = config->P1; + REAL P2 = config->P2; + REAL P3 = config->P3; + //REAL P4 = config->P4; + REAL P5 = config->P5; + REAL P6 = config->P6; + REAL P7 = config->P7; + REAL P8 = config->P8; + REAL P9 = config->P9; + REAL P10 = config->P10; @@ -140,11 +140,11 @@ void threshold_func(config_t *restrict config) + P5*((muV-muV0)/DmuV0)*((muV-muV0)/DmuV0)\ + P6*((sV-sV0)/DsV0)*((sV-sV0)/DsV0)\ + P7*((TvN-TvN0)/DTvN0)*((TvN-TvN0)/DTvN0)\ - + P8*(muV-muV0)/DmuV0*(sV-sV0)/DsV0\ - + P9*(muV-muV0)/DmuV0*(TvN-TvN0)/DTvN0\ - + P10*(sV-sV0)/DsV0*(TvN-TvN0)/DTvN0; + + P8*((muV-muV0)/DmuV0)*((sV-sV0)/DsV0)\ + + P9*((muV-muV0)/DmuV0)*((TvN-TvN0)/DTvN0)\ + + P10*((sV-sV0)/DsV0)*((TvN-TvN0)/DTvN0); - //config->Vthre = config->P0; + config->Vthre = Vthre; } diff --git a/neural_modelling/src/meanfield/models/meanfield_model_impl.h b/neural_modelling/src/meanfield/models/meanfield_model_impl.h index 7baa3338fc7..deed2353274 100644 --- a/neural_modelling/src/meanfield/models/meanfield_model_impl.h +++ b/neural_modelling/src/meanfield/models/meanfield_model_impl.h @@ -21,6 +21,7 @@ #define _MEANFIELD_MODEL_IMPL_H_ #include "../../meanfield/models/meanfield_model.h" +//#include typedef struct meanfield_t { // TODO: Parameters - make sure these match with the Python code, From 9b2d57774723e1a66d9ad329b95a103538c779fb Mon Sep 17 00:00:00 2001 From: Garandel Date: Fri, 15 Oct 2021 14:22:58 +0000 Subject: [PATCH 13/44] clean and remove sqrtk indicated when with coms, just to try without optimisation yet --- .../meanfield/models/meanfield_model_impl.c | 44 ++++++++++++------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/neural_modelling/src/meanfield/models/meanfield_model_impl.c b/neural_modelling/src/meanfield/models/meanfield_model_impl.c index f036a503439..c71c84e1fd7 100644 --- a/neural_modelling/src/meanfield/models/meanfield_model_impl.c +++ b/neural_modelling/src/meanfield/models/meanfield_model_impl.c @@ -148,7 +148,6 @@ void threshold_func(config_t *restrict config) } -/* // REAL ONE get_fluct_regime_varsup void get_fluct_regime_varsup(REAL Ve, REAL Vi, config_t *restrict params) { @@ -182,22 +181,29 @@ void get_fluct_regime_varsup(REAL Ve, REAL Vi, config_t *restrict params) Ui = params->Qi/muG*(params->Ei-params->muV); - //PENSEZ a enlever autant de division que possible + /* + normalement sqrt((Fe*(Ue*params->Te)*(Ue*params->Te)/2./(params->Te+Tm)+\ + Fi*(params->Ti*Ui)*(params->Ti*Ui)/2./(params->Ti+Tm))) + + doit trouver une bonne focntion pour faire sqrt ... + |->sqrtk() ne fonctionne pas + */ + - params->sV = sqrtk(Fe*(Ue*params->Te)*(Ue*params->Te)/2./(params->Te+Tm)+\ + params->sV = (Fe*(Ue*params->Te)*(Ue*params->Te)/2./(params->Te+Tm)+\ Fi*(params->Ti*Ui)*(params->Ti*Ui)/2./(params->Ti+Tm)); - if (params->sV < 1e-8){ - params->sV = 1e-8; + if (params->sV < ACS_DBL_TINY){ + params->sV = ACS_DBL_TINY; } - if (Fe<1e-9)//just to insure a non zero division, + if (FeTe)*(Ue*params->Te) + Fi*(params->Ti*Ui)*(params->Ti*Ui))\ @@ -209,9 +215,8 @@ void get_fluct_regime_varsup(REAL Ve, REAL Vi, config_t *restrict params) //return params->muV;//, sV+1e-12, muGn, TvN } //END of the REAL get_fluct_regime_varsup -*/ - +/* // FAKE ONE get_fluct_regime_varsup //where all division are removed @@ -273,7 +278,8 @@ void get_fluct_regime_varsup(REAL Ve, REAL Vi, config_t *restrict params) //return params->muV;//, sV+1e-12, muGn, TvN } -//END of the FAKE get_fluct_regime_varsup +//END of the FAKE get_fluct_regime_varsup +*/ @@ -303,8 +309,14 @@ void TF(REAL Ve, REAL Vi, meanfield_t *meanfield, config_t *restrict config, config->sV = REAL_CONST(1e-4); } - limit = 10;//REAL_HALF(config->Gl/(config->TvN * config->Cm)); - argument = config->Vthre;//(config->Vthre - config->muV)/sqrtk(REAL_CONST(2.))/config->sV; + limit = 0.5*(config->Gl/(config->TvN * config->Cm)); + /* + normalement sqrt: + argument = (config->Vthre - config->muV)/sqrtk(REAL_CONST(2.))/config->sV; + + */ + + argument = (config->Vthre - config->muV)/(REAL_CONST(2.))/config->sV; // config->Fout_th = error_function(factor, argument, mathsbox); error_function(limit, argument, mathsbox); @@ -325,8 +337,8 @@ on the user computer before send it to the DTCM. */ REAL lastVe = meanfield->Ve; REAL T_inv = meanfield->Timescale_inv; - //TF(lastVe,1.,meanfield, config, mathsbox); - REAL lastTF = ONE; //config->Fout_th; + TF(lastVe,1.,meanfield, config, mathsbox); + REAL lastTF = config->Fout_th; //configVe stand for TF1 i.e TF for exitatory pop. SO configVi is for TF2 //In fact no configVe and configVi just config, all in the same file. From e41ac1d819476c87b4ccd1f10651650b9c13eeec Mon Sep 17 00:00:00 2001 From: Garandel Date: Mon, 18 Oct 2021 13:08:16 +0000 Subject: [PATCH 14/44] remove FAKEs (where no divisions) to clean a little bits, --- neural_modelling/src/meanfield/models/meanfield_model_impl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/neural_modelling/src/meanfield/models/meanfield_model_impl.c b/neural_modelling/src/meanfield/models/meanfield_model_impl.c index c71c84e1fd7..1a1211127af 100644 --- a/neural_modelling/src/meanfield/models/meanfield_model_impl.c +++ b/neural_modelling/src/meanfield/models/meanfield_model_impl.c @@ -185,8 +185,8 @@ void get_fluct_regime_varsup(REAL Ve, REAL Vi, config_t *restrict params) normalement sqrt((Fe*(Ue*params->Te)*(Ue*params->Te)/2./(params->Te+Tm)+\ Fi*(params->Ti*Ui)*(params->Ti*Ui)/2./(params->Ti+Tm))) - doit trouver une bonne focntion pour faire sqrt ... - |->sqrtk() ne fonctionne pas + doit trouver une bonne fonction pour faire sqrt ... + |->sqrtk() ne fonctionne pas !!! */ From 07d31703910ed94fcebb1978ad5abd1843a7126f Mon Sep 17 00:00:00 2001 From: Garandel Date: Mon, 18 Oct 2021 13:08:39 +0000 Subject: [PATCH 15/44] remove FAKEs (where no divisions) to clean a little bits, --- .../meanfield/models/meanfield_model_impl.c | 66 ------------------- 1 file changed, 66 deletions(-) diff --git a/neural_modelling/src/meanfield/models/meanfield_model_impl.c b/neural_modelling/src/meanfield/models/meanfield_model_impl.c index 1a1211127af..8f26cf83ba8 100644 --- a/neural_modelling/src/meanfield/models/meanfield_model_impl.c +++ b/neural_modelling/src/meanfield/models/meanfield_model_impl.c @@ -216,72 +216,6 @@ void get_fluct_regime_varsup(REAL Ve, REAL Vi, config_t *restrict params) } //END of the REAL get_fluct_regime_varsup -/* -// FAKE ONE get_fluct_regime_varsup -//where all division are removed - -void get_fluct_regime_varsup(REAL Ve, REAL Vi, config_t *restrict params) -{ - //takes 880 bytes overflowed ITCM - - REAL Fe; - REAL Fi; - REAL muGe, muGi, muG; - REAL Ue, Ui; - REAL Tm, Tv; - - - // here TOTAL (sum over synapses) excitatory and inhibitory input - - Fe = Ve * (ONE-params->gei)*params->pconnec*params->Ntot; // default is 1 !! - Fi = Vi * params->gei*params->pconnec*params->Ntot; - - muGe = params->Qe*params->Te*Ve; - muGi = params->Qi*params->Ti*Vi; - - muG = params->Gl+muGe+muGi; - - params->muV = (muGe*params->Ee+muGi*params->Ei+params->Gl*params->El); //fake one - - params->muGn = muG; //fake one - - Tm = params->Cm/muG; //fake one - - Ue = params->Qe; //fake one - Ui = params->Qi; //fake one - - - //PENSEZ a enlever autant de division que possible - - params->sV = Fe*(Ue*params->Te)*(Ue*params->Te)+\ - Fi*(params->Ti*Ui)*(params->Ti*Ui);// fake one - - if (params->sV < ACS_DBL_TINY){ - params->sV = ACS_DBL_TINY; - } - - if (FeTe)*(Ue*params->Te) +\ - Fi*(params->Ti*Ui)*(params->Ti*Ui)); //fake one - - params->TvN = Tv*params->Gl; //fake one - - - //return params->muV;//, sV+1e-12, muGn, TvN -} - -//END of the FAKE get_fluct_regime_varsup -*/ - - void TF(REAL Ve, REAL Vi, meanfield_t *meanfield, config_t *restrict config, mathsbox_t *restrict mathsbox){ From 8cdb775d1f7cf55d61710713dd3c5e74056c38a7 Mon Sep 17 00:00:00 2001 From: Garandel Date: Mon, 18 Oct 2021 15:44:01 +0000 Subject: [PATCH 16/44] add Vi --- .../meanfield/models/meanfield_model_impl.c | 37 ++++++++++++++----- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/neural_modelling/src/meanfield/models/meanfield_model_impl.c b/neural_modelling/src/meanfield/models/meanfield_model_impl.c index 8f26cf83ba8..88cb1c7eaf6 100644 --- a/neural_modelling/src/meanfield/models/meanfield_model_impl.c +++ b/neural_modelling/src/meanfield/models/meanfield_model_impl.c @@ -169,6 +169,10 @@ void get_fluct_regime_varsup(REAL Ve, REAL Vi, config_t *restrict params) muGi = params->Qi*params->Ti*Vi; muG = params->Gl+muGe+muGi; + + if (muG < ACS_DBL_TINY){ + muG = ACS_DBL_TINY; + } params->muV = (muGe*params->Ee+muGi*params->Ei+params->Gl*params->El)/muG; @@ -194,7 +198,7 @@ void get_fluct_regime_varsup(REAL Ve, REAL Vi, config_t *restrict params) Fi*(params->Ti*Ui)*(params->Ti*Ui)/2./(params->Ti+Tm)); if (params->sV < ACS_DBL_TINY){ - params->sV = ACS_DBL_TINY; + params->sV += ACS_DBL_TINY; } if (FeTe)*(Ue*params->Te) + Fi*(params->Ti*Ui)*(params->Ti*Ui))\ /(Fe*(Ue*params->Te)*(Ue*params->Te)/(params->Te+Tm)\ + Fi*(params->Ti*Ui)*(params->Ti*Ui)/(params->Ti+Tm)); @@ -239,8 +243,8 @@ void TF(REAL Ve, REAL Vi, meanfield_t *meanfield, config_t *restrict config, get_fluct_regime_varsup(Ve, Vi, config); threshold_func(config); - if (config->sVsV = REAL_CONST(1e-4); + if (config->sVsV = ACS_DBL_TINY; } limit = 0.5*(config->Gl/(config->TvN * config->Cm)); @@ -254,6 +258,8 @@ void TF(REAL Ve, REAL Vi, meanfield_t *meanfield, config_t *restrict config, // config->Fout_th = error_function(factor, argument, mathsbox); error_function(limit, argument, mathsbox); + //config->Fout_th = (0.5*config->Gl) * mathsbox->err_func / (config->Cm*config->TvN) ; REAL ONE + config->Fout_th = mathsbox->err_func ; //TEST if (config->Fout_th < ACS_DBL_TINY){ @@ -270,10 +276,16 @@ void RK2_midpoint_MF(REAL h, meanfield_t *meanfield, config_t *restrict config, on the user computer before send it to the DTCM. */ REAL lastVe = meanfield->Ve; + REAL lastVi = meanfield->Vi; + + if (lastVi < ACS_DBL_TINY){ + lastVi = ACS_DBL_TINY; + } + REAL T_inv = meanfield->Timescale_inv; - TF(lastVe,1.,meanfield, config, mathsbox); + TF(lastVe, lastVi, meanfield, config, mathsbox); REAL lastTF = config->Fout_th; - + //configVe stand for TF1 i.e TF for exitatory pop. SO configVi is for TF2 //In fact no configVe and configVi just config, all in the same file. @@ -283,8 +295,15 @@ on the user computer before send it to the DTCM. *(REAL_CONST(2.0)-h)*h; */ - meanfield->Ve += lastVe + (REAL_HALF(lastTF - lastVe) * (REAL_CONST(2.0)-h) * h); + meanfield->Ve += lastVe \ + + (REAL_HALF(lastTF - lastVe) * (REAL_CONST(2.0)-h) * h); meanfield->Ve = meanfield->Ve * T_inv; + + meanfield->Vi += lastVi \ + + (REAL_HALF(lastTF - lastVi) * (REAL_CONST(2.0)-h) * h); + meanfield->Vi = meanfield->Vi * T_inv; + + } @@ -383,11 +402,11 @@ state_t meanfield_model_get_firing_rate(const meanfield_t *meanfield) { void meanfield_model_print_state_variables(const meanfield_t *meanfield) { log_debug("Ve = %11.4k ", meanfield->Ve); - //log_debug("U = %11.4k ", meanfield->Vi); + log_debug("Vi = %11.4k ", meanfield->Vi); } void meanfield_model_print_parameters(const meanfield_t *meanfield) { - log_debug("Ve = %11.4k ", meanfield->Ve); + //log_debug("Ve = %11.4k ", meanfield->Ve); //log_debug("Vi = %11.4k ", meanfield->Vi); //log_debug("B = %11.4k ", neuron->B); //log_debug("C = %11.4k ", neuron->C); From d608f1c48e7d598c68d23af7fdebe69a183a4432 Mon Sep 17 00:00:00 2001 From: Garandel Date: Mon, 18 Oct 2021 15:44:14 +0000 Subject: [PATCH 17/44] modified: meanfield/models/meanfield_model_impl.h modified: ../../spynnaker/pyNN/models/neuron/builds/meanfield_base.py modified: ../../spynnaker/pyNN/models/neuron/implementations/meanfield_impl_standard.py modified: ../../spynnaker/pyNN/models/neuron/neuron_models/config.py modified: ../../spynnaker/pyNN/models/neuron/neuron_models/meanfield_model_eitn.py ADD Vi and put it like state_variables CHANGE muV from state_variables to parameters --- .../meanfield/models/meanfield_model_impl.h | 2 +- .../models/neuron/builds/meanfield_base.py | 5 +++-- .../meanfield_impl_standard.py | 6 +++--- .../models/neuron/neuron_models/config.py | 9 ++++---- .../neuron_models/meanfield_model_eitn.py | 21 ++++++++++++++++--- 5 files changed, 30 insertions(+), 13 deletions(-) diff --git a/neural_modelling/src/meanfield/models/meanfield_model_impl.h b/neural_modelling/src/meanfield/models/meanfield_model_impl.h index deed2353274..8030362ae51 100644 --- a/neural_modelling/src/meanfield/models/meanfield_model_impl.h +++ b/neural_modelling/src/meanfield/models/meanfield_model_impl.h @@ -40,7 +40,7 @@ typedef struct meanfield_t { REAL Timescale_inv; REAL Ve; // will be used as a vector !!! OR Ve and Vi - //REAL Vi; + REAL Vi; //vector V = {Ve, Vi}; diff --git a/spynnaker/pyNN/models/neuron/builds/meanfield_base.py b/spynnaker/pyNN/models/neuron/builds/meanfield_base.py index 6c8e2c82055..257a0eb243f 100644 --- a/spynnaker/pyNN/models/neuron/builds/meanfield_base.py +++ b/spynnaker/pyNN/models/neuron/builds/meanfield_base.py @@ -70,7 +70,7 @@ class MeanfieldBase(AbstractPyNNMeanfieldModelStandard): """ # noinspection PyPep8Naming - @default_initial_values({"Ve", "muV", "sV", "muGn", "TvN", "Vthre", + @default_initial_values({"Ve", "Vi", "sV", "muGn", "TvN", "Vthre", "Fout_th", "err_func", "isyn_exc", "isyn_inh"}) def __init__(self, nbr=1, @@ -83,6 +83,7 @@ def __init__(self, ampnoise=0.0, Timescale_inv=0.5, Ve=0., + Vi=0.1, pconnec=0.05, q_exc=1.5, @@ -142,7 +143,7 @@ def __init__(self, # pylint: disable=too-many-arguments, too-many-locals neuron_model = MeanfieldModelEitn(nbr, a, b, tauw, Trefrac, Vreset, delta_v, ampnoise, - Timescale_inv, Ve) + Timescale_inv, Ve, Vi) config = Config(pconnec, q_exc, q_inh, Tsyn_exc, Tsyn_inh, Erev_exc, Erev_inh, diff --git a/spynnaker/pyNN/models/neuron/implementations/meanfield_impl_standard.py b/spynnaker/pyNN/models/neuron/implementations/meanfield_impl_standard.py index ac2008f81ae..58c92509605 100644 --- a/spynnaker/pyNN/models/neuron/implementations/meanfield_impl_standard.py +++ b/spynnaker/pyNN/models/neuron/implementations/meanfield_impl_standard.py @@ -48,7 +48,7 @@ class MeanfieldImplStandard(AbstractNeuronImpl): ] # _RECORDABLES = ["Ve", "gsyn_exc", "gsyn_inh"] - _RECORDABLES = ["Ve", "muV", "sV", "muGn", "TvN", "Vthre", + _RECORDABLES = ["Ve", "Vi", "sV", "muGn", "TvN", "Vthre", "Fout_th", "err_func", "gsyn_exc", "gsyn_inh"] # _RECORDABLE_DATA_TYPES = { @@ -58,7 +58,7 @@ class MeanfieldImplStandard(AbstractNeuronImpl): # } _RECORDABLE_DATA_TYPES = { "Ve": DataType.S1615, - "muV": DataType.S1615, + "Vi": DataType.S1615, "sV": DataType.S1615, "muGn": DataType.S1615, "TvN": DataType.S1615, @@ -76,7 +76,7 @@ class MeanfieldImplStandard(AbstractNeuronImpl): # } _RECORDABLE_UNITS = { 'Ve': 'mV', - 'muV': "uS", + 'Vi': "mV", 'sV': "uS", 'TvN': 'mV', 'Vthre': "uS", diff --git a/spynnaker/pyNN/models/neuron/neuron_models/config.py b/spynnaker/pyNN/models/neuron/neuron_models/config.py index 800e5616a14..25c917df257 100644 --- a/spynnaker/pyNN/models/neuron/neuron_models/config.py +++ b/spynnaker/pyNN/models/neuron/neuron_models/config.py @@ -281,6 +281,7 @@ def add_parameters(self, parameters): parameters[P8] = self._p8 parameters[P9] = self._p9 parameters[P10] = self._p10 + parameters[MUV] = self._muV parameters[MUV0] = self._muV0 parameters[DMUV0] = self._DmuV0 parameters[SV0] = self._sV0 @@ -290,7 +291,7 @@ def add_parameters(self, parameters): @overrides(AbstractStandardNeuronComponent.add_state_variables) def add_state_variables(self, state_variables): - state_variables[MUV] = self._muV + #state_variables[MUV] = self._muV state_variables[SV] = self._sV state_variables[MUGN] = self._muGn state_variables[TVN] = self._TvN @@ -343,7 +344,7 @@ def get_values(self, parameters, state_variables, vertex_slice, ts): parameters[P8], parameters[P9], parameters[P10], - state_variables[MUV], + parameters[MUV], parameters[MUV0], parameters[DMUV0], state_variables[SV], @@ -367,14 +368,14 @@ def update_values(self, values, parameters, state_variables): _Gl, _Cm, _El, _p0, _p1, _p2, _p3, _p4, _p5, _p6, _p7, _p8, _p9, _p10, - muV, _muV0, _DmuV0, + _muV, _muV0, _DmuV0, sV, _sV0, _DsV0, muGn, TvN, _TvN0, _DTvN0, Vthre, Fout_th) = values # Copy the changed data only - state_variables[MUV] = muV + #state_variables[MUV] = muV state_variables[SV] = sV state_variables[MUGN] = muGn state_variables[TVN] = TvN diff --git a/spynnaker/pyNN/models/neuron/neuron_models/meanfield_model_eitn.py b/spynnaker/pyNN/models/neuron/neuron_models/meanfield_model_eitn.py index 50c8f5d55fd..7caa8cde165 100644 --- a/spynnaker/pyNN/models/neuron/neuron_models/meanfield_model_eitn.py +++ b/spynnaker/pyNN/models/neuron/neuron_models/meanfield_model_eitn.py @@ -31,6 +31,7 @@ AMPNOISE = "ampnoise" TIMESCALE_INV = "Timescale_inv" VE = "Ve" +VI = "Vi" UNITS = { ###--Meanfield--### @@ -44,6 +45,7 @@ AMPNOISE: "Hz", TIMESCALE_INV: "Hz", VE: "Hz", + VI: "Hz", } @@ -52,12 +54,12 @@ class MeanfieldModelEitn(AbstractNeuronModel): """ __slots__ = [ "_nbr", "_a", "_b", "_tauw", "_Trefrac", "_Vreset", "_delta_v", - "_ampnoise", "_Timescale_inv", "_Ve_init" + "_ampnoise", "_Timescale_inv", "_Ve_init", "_Vi_init", ] def __init__(self, nbr, a, b, tauw, Trefrac, Vreset, delta_v, - ampnoise, Timescale_inv, Ve_init): + ampnoise, Timescale_inv, Ve_init, Vi_init): """ :param a: :math:`a` :type a: float, iterable(float), ~pyNN.random.RandomDistribution or @@ -95,6 +97,7 @@ def __init__(self, nbr, a, b, tauw, DataType.S1615, #ampnoise DataType.S1615, #Timescale_inv DataType.S1615, #Ve + DataType.S1615, #Vi DataType.S1615], # this_h (= machine_time_step) [DataType.S1615]) # machine_time_step self._nbr = nbr @@ -107,6 +110,7 @@ def __init__(self, nbr, a, b, tauw, self._ampnoise = ampnoise self._Timescale_inv = Timescale_inv self._Ve_init = Ve_init + self._Vi_init = Vi_init @overrides(AbstractStandardNeuronComponent.get_n_cpu_cycles) def get_n_cpu_cycles(self, n_neurons): @@ -129,6 +133,7 @@ def add_parameters(self, parameters): @overrides(AbstractStandardNeuronComponent.add_state_variables) def add_state_variables(self, state_variables): state_variables[VE] = self._Ve_init + state_variables[VI] = self._Vi_init #state_variables[U] = self.__u_init @overrides(AbstractStandardNeuronComponent.get_units) @@ -158,6 +163,7 @@ def get_values(self, parameters, state_variables, vertex_slice, ts): parameters[VRESET],parameters[DELTA_V],parameters[AMPNOISE], parameters[TIMESCALE_INV], state_variables[VE], + state_variables[VI], float(ts) / MICRO_TO_MILLISECOND_CONVERSION ] @@ -167,10 +173,11 @@ def update_values(self, values, parameters, state_variables): # Decode the values (_nbr, _a, _b, _tauw, _Trefrac, _Vreset, _delta_v, - _ampnoise, _Timescale_inv, Ve, _this_h) = values + _ampnoise, _Timescale_inv, Ve, Vi, _this_h) = values # Copy the changed data only state_variables[VE] = Ve + state_variables[VI] = Vi #state_variables[U] = u ################ @@ -222,3 +229,11 @@ def Ve_init(self): """ return self._Ve_init + @property + def Vi_init(self): + """ Settable model parameter: :math:`V_{i}` + + :rtype: float + """ + return self._Vi_init + From d89ccb255ceab25f412521f66ffb96a4c11762d6 Mon Sep 17 00:00:00 2001 From: Garandel Date: Tue, 19 Oct 2021 08:58:22 +0000 Subject: [PATCH 18/44] modified: meanfield/models/meanfield_model_impl.c modified: ../../spynnaker/pyNN/models/neuron/builds/meanfield_base.py modified: ../../spynnaker/pyNN/models/neuron/implementations/meanfield_impl_standard.py modified: ../../spynnaker/pyNN/models/neuron/neuron_models/config.py pbl when add Vi obtain DIBBY0 error but now clue where. --- .../src/meanfield/models/meanfield_model_impl.c | 8 ++++++-- spynnaker/pyNN/models/neuron/builds/meanfield_base.py | 4 ++-- .../neuron/implementations/meanfield_impl_standard.py | 3 +++ spynnaker/pyNN/models/neuron/neuron_models/config.py | 10 +++++----- 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/neural_modelling/src/meanfield/models/meanfield_model_impl.c b/neural_modelling/src/meanfield/models/meanfield_model_impl.c index 88cb1c7eaf6..95b757d6808 100644 --- a/neural_modelling/src/meanfield/models/meanfield_model_impl.c +++ b/neural_modelling/src/meanfield/models/meanfield_model_impl.c @@ -164,14 +164,14 @@ void get_fluct_regime_varsup(REAL Ve, REAL Vi, config_t *restrict params) Fe = Ve * (1.-params->gei)*params->pconnec*params->Ntot; // default is 1 !! Fi = Vi * params->gei*params->pconnec*params->Ntot; - + muGe = params->Qe*params->Te*Ve; muGi = params->Qi*params->Ti*Vi; muG = params->Gl+muGe+muGi; if (muG < ACS_DBL_TINY){ - muG = ACS_DBL_TINY; + muG += ACS_DBL_TINY; } params->muV = (muGe*params->Ee+muGi*params->Ei+params->Gl*params->El)/muG; @@ -213,6 +213,10 @@ void get_fluct_regime_varsup(REAL Ve, REAL Vi, config_t *restrict params) Tv = ( Fe*(Ue*params->Te)*(Ue*params->Te) + Fi*(params->Ti*Ui)*(params->Ti*Ui))\ /(Fe*(Ue*params->Te)*(Ue*params->Te)/(params->Te+Tm)\ + Fi*(params->Ti*Ui)*(params->Ti*Ui)/(params->Ti+Tm)); + + if (Tv < ACS_DBL_TINY){ + Tv += ACS_DBL_TINY; + } params->TvN = Tv*params->Gl/params->Cm; diff --git a/spynnaker/pyNN/models/neuron/builds/meanfield_base.py b/spynnaker/pyNN/models/neuron/builds/meanfield_base.py index 257a0eb243f..b11884577be 100644 --- a/spynnaker/pyNN/models/neuron/builds/meanfield_base.py +++ b/spynnaker/pyNN/models/neuron/builds/meanfield_base.py @@ -70,7 +70,7 @@ class MeanfieldBase(AbstractPyNNMeanfieldModelStandard): """ # noinspection PyPep8Naming - @default_initial_values({"Ve", "Vi", "sV", "muGn", "TvN", "Vthre", + @default_initial_values({"Ve", "Vi", "muV", "sV", "muGn", "TvN", "Vthre", "Fout_th", "err_func", "isyn_exc", "isyn_inh"}) def __init__(self, nbr=1, @@ -83,7 +83,7 @@ def __init__(self, ampnoise=0.0, Timescale_inv=0.5, Ve=0., - Vi=0.1, + Vi=1., pconnec=0.05, q_exc=1.5, diff --git a/spynnaker/pyNN/models/neuron/implementations/meanfield_impl_standard.py b/spynnaker/pyNN/models/neuron/implementations/meanfield_impl_standard.py index 58c92509605..d8f1cd153d2 100644 --- a/spynnaker/pyNN/models/neuron/implementations/meanfield_impl_standard.py +++ b/spynnaker/pyNN/models/neuron/implementations/meanfield_impl_standard.py @@ -59,6 +59,7 @@ class MeanfieldImplStandard(AbstractNeuronImpl): _RECORDABLE_DATA_TYPES = { "Ve": DataType.S1615, "Vi": DataType.S1615, + #"muV": DataType.S1615, "sV": DataType.S1615, "muGn": DataType.S1615, "TvN": DataType.S1615, @@ -77,7 +78,9 @@ class MeanfieldImplStandard(AbstractNeuronImpl): _RECORDABLE_UNITS = { 'Ve': 'mV', 'Vi': "mV", + #'muV': "uS", 'sV': "uS", + 'muGn':"uS", 'TvN': 'mV', 'Vthre': "uS", 'Fout_th': "uS", diff --git a/spynnaker/pyNN/models/neuron/neuron_models/config.py b/spynnaker/pyNN/models/neuron/neuron_models/config.py index 25c917df257..64658f26c46 100644 --- a/spynnaker/pyNN/models/neuron/neuron_models/config.py +++ b/spynnaker/pyNN/models/neuron/neuron_models/config.py @@ -281,7 +281,7 @@ def add_parameters(self, parameters): parameters[P8] = self._p8 parameters[P9] = self._p9 parameters[P10] = self._p10 - parameters[MUV] = self._muV + #parameters[MUV] = self._muV parameters[MUV0] = self._muV0 parameters[DMUV0] = self._DmuV0 parameters[SV0] = self._sV0 @@ -291,7 +291,7 @@ def add_parameters(self, parameters): @overrides(AbstractStandardNeuronComponent.add_state_variables) def add_state_variables(self, state_variables): - #state_variables[MUV] = self._muV + state_variables[MUV] = self._muV state_variables[SV] = self._sV state_variables[MUGN] = self._muGn state_variables[TVN] = self._TvN @@ -344,7 +344,7 @@ def get_values(self, parameters, state_variables, vertex_slice, ts): parameters[P8], parameters[P9], parameters[P10], - parameters[MUV], + state_variables[MUV], parameters[MUV0], parameters[DMUV0], state_variables[SV], @@ -368,14 +368,14 @@ def update_values(self, values, parameters, state_variables): _Gl, _Cm, _El, _p0, _p1, _p2, _p3, _p4, _p5, _p6, _p7, _p8, _p9, _p10, - _muV, _muV0, _DmuV0, + muV, _muV0, _DmuV0, sV, _sV0, _DsV0, muGn, TvN, _TvN0, _DTvN0, Vthre, Fout_th) = values # Copy the changed data only - #state_variables[MUV] = muV + state_variables[MUV] = muV state_variables[SV] = sV state_variables[MUGN] = muGn state_variables[TVN] = TvN From dcf8d3565d6af163513e73925e998f1b590fe788 Mon Sep 17 00:00:00 2001 From: Garandel Date: Tue, 19 Oct 2021 14:38:12 +0000 Subject: [PATCH 19/44] modified: meanfield/implementations/meanfield_impl_standard.h modified: meanfield/models/meanfield_model_impl.c modified: meanfield/models/meanfield_model_impl.h modified: ../../spynnaker/pyNN/models/neuron/builds/meanfield_base.py modified: ../../spynnaker/pyNN/models/neuron/implementations/meanfield_impl_standard.py modified: ../../spynnaker/pyNN/models/neuron/neuron_models/meanfield_model_eitn.py try to solved the error DIVBY0 and pass from 10 vars recorded to 5. --- .../implementations/meanfield_impl_standard.h | 2 +- .../meanfield/models/meanfield_model_impl.c | 46 +++++++++---------- .../meanfield/models/meanfield_model_impl.h | 6 +-- .../models/neuron/builds/meanfield_base.py | 4 +- .../meanfield_impl_standard.py | 45 +++++++++++------- .../neuron_models/meanfield_model_eitn.py | 3 +- 6 files changed, 56 insertions(+), 50 deletions(-) diff --git a/neural_modelling/src/meanfield/implementations/meanfield_impl_standard.h b/neural_modelling/src/meanfield/implementations/meanfield_impl_standard.h index 59e60b7ea3b..9d843e0065a 100644 --- a/neural_modelling/src/meanfield/implementations/meanfield_impl_standard.h +++ b/neural_modelling/src/meanfield/implementations/meanfield_impl_standard.h @@ -46,7 +46,7 @@ enum word_recording_indices { //! Gsyn_inh (excitatory synaptic conductance/current) recording index GSYN_INH_RECORDING_INDEX = 2, //! Number of recorded word-sized state variables - N_RECORDED_VARS = 10 + N_RECORDED_VARS = 5 }; //! Indices for recording of bitfields diff --git a/neural_modelling/src/meanfield/models/meanfield_model_impl.c b/neural_modelling/src/meanfield/models/meanfield_model_impl.c index 95b757d6808..902a299db2b 100644 --- a/neural_modelling/src/meanfield/models/meanfield_model_impl.c +++ b/neural_modelling/src/meanfield/models/meanfield_model_impl.c @@ -22,6 +22,7 @@ #include #include "../../meanfield/models/config.h" #include "../../meanfield/models/mathsbox.h" +//#include "../../common/maths-util.h" // i.o to use SQRT(x) and SQR(a) //! The global parameters of the Izhekevich neuron model static const global_neuron_params_t *global_params; @@ -73,7 +74,7 @@ void error_function( REAL x, REAL factor, mathsbox_t *restrict mathsbox){ REAL dt = x/mathsbox->error_func_sample; REAL t; //REAL Pi = 3.1415927;// here was a k - REAL two_over_sqrt_Pi = 1.128379167; //APPROXIMATION + REAL two_over_sqrt_Pi = REAL_CONST(1.128379167); //APPROXIMATION REAL Erfc = mathsbox->err_func; for(t=0; t==x; t+=dt){ //Erfc += dt; //test otherwise ITCM overload @@ -162,7 +163,7 @@ void get_fluct_regime_varsup(REAL Ve, REAL Vi, config_t *restrict params) // here TOTAL (sum over synapses) excitatory and inhibitory input - Fe = Ve * (1.-params->gei)*params->pconnec*params->Ntot; // default is 1 !! + Fe = Ve * (REAL_CONST(1.)-params->gei)*params->pconnec*params->Ntot; // default is 1 !! Fi = Vi * params->gei*params->pconnec*params->Ntot; muGe = params->Qe*params->Te*Ve; @@ -194,13 +195,9 @@ void get_fluct_regime_varsup(REAL Ve, REAL Vi, config_t *restrict params) */ - params->sV = (Fe*(Ue*params->Te)*(Ue*params->Te)/2./(params->Te+Tm)+\ - Fi*(params->Ti*Ui)*(params->Ti*Ui)/2./(params->Ti+Tm)); - - if (params->sV < ACS_DBL_TINY){ - params->sV += ACS_DBL_TINY; - } - + params->sV = Fe*(Ue*params->Te)*(Ue*params->Te)/REAL_CONST(2.)/(params->Te+Tm)\ + + Fi*(params->Ti*Ui)*(params->Ti*Ui)/REAL_CONST(2.)/(params->Ti+Tm); + if (FesVsV = ACS_DBL_TINY; + config->sV += ACS_DBL_TINY; } - limit = 0.5*(config->Gl/(config->TvN * config->Cm)); + limit = REAL_CONST(0.5)*(config->Gl/(config->TvN * config->Cm)); /* normalement sqrt: argument = (config->Vthre - config->muV)/sqrtk(REAL_CONST(2.))/config->sV; */ - argument = (config->Vthre - config->muV)/(REAL_CONST(2.))/config->sV; + argument = (config->Vthre - config->muV)/(REAL_CONST(1.4142137))/config->sV; // config->Fout_th = error_function(factor, argument, mathsbox); error_function(limit, argument, mathsbox); - //config->Fout_th = (0.5*config->Gl) * mathsbox->err_func / (config->Cm*config->TvN) ; REAL ONE - config->Fout_th = mathsbox->err_func ; //TEST + config->Fout_th = (HALF*config->Gl) * mathsbox->err_func / (config->Cm*config->TvN) ;// REAL ONE + //config->Fout_th = mathsbox->err_func ; //TEST if (config->Fout_th < ACS_DBL_TINY){ - config->Fout_th = ACS_DBL_TINY; + config->Fout_th += ACS_DBL_TINY; } //return config->Fout_th; @@ -283,13 +280,13 @@ on the user computer before send it to the DTCM. REAL lastVi = meanfield->Vi; if (lastVi < ACS_DBL_TINY){ - lastVi = ACS_DBL_TINY; + lastVi += ACS_DBL_TINY; } REAL T_inv = meanfield->Timescale_inv; - TF(lastVe, lastVi, meanfield, config, mathsbox); - REAL lastTF = config->Fout_th; + TF(1., lastVi, meanfield, config, mathsbox); + REAL lastTF = config->Fout_th; //configVe stand for TF1 i.e TF for exitatory pop. SO configVi is for TF2 //In fact no configVe and configVi just config, all in the same file. @@ -299,13 +296,12 @@ on the user computer before send it to the DTCM. *(REAL_CONST(2.0)-h)*h; */ - meanfield->Ve += lastVe \ - + (REAL_HALF(lastTF - lastVe) * (REAL_CONST(2.0)-h) * h); + meanfield->Ve += lastVe + (REAL_HALF(lastTF - lastVe) * (REAL_CONST(2.0)-h) * h); meanfield->Ve = meanfield->Ve * T_inv; - meanfield->Vi += lastVi \ - + (REAL_HALF(lastTF - lastVi) * (REAL_CONST(2.0)-h) * h); - meanfield->Vi = meanfield->Vi * T_inv; + meanfield->Vi += lastVi; + //meanfield->Vi += T_inv*(lastVi + (REAL_HALF(lastTF - lastVi) * (REAL_CONST(2.0)-h) * h)); + //meanfield->Vi = meanfield->Vi * T_inv; } diff --git a/neural_modelling/src/meanfield/models/meanfield_model_impl.h b/neural_modelling/src/meanfield/models/meanfield_model_impl.h index 8030362ae51..3e6cff7caea 100644 --- a/neural_modelling/src/meanfield/models/meanfield_model_impl.h +++ b/neural_modelling/src/meanfield/models/meanfield_model_impl.h @@ -39,11 +39,9 @@ typedef struct meanfield_t { REAL ampnoise; REAL Timescale_inv; - REAL Ve; // will be used as a vector !!! OR Ve and Vi + REAL Ve; REAL Vi; - - //vector V = {Ve, Vi}; - + REAL this_h; diff --git a/spynnaker/pyNN/models/neuron/builds/meanfield_base.py b/spynnaker/pyNN/models/neuron/builds/meanfield_base.py index b11884577be..959f69a639e 100644 --- a/spynnaker/pyNN/models/neuron/builds/meanfield_base.py +++ b/spynnaker/pyNN/models/neuron/builds/meanfield_base.py @@ -82,8 +82,8 @@ def __init__(self, delta_v=-0.5, ampnoise=0.0, Timescale_inv=0.5, - Ve=0., - Vi=1., + Ve=9., + Vi=23., pconnec=0.05, q_exc=1.5, diff --git a/spynnaker/pyNN/models/neuron/implementations/meanfield_impl_standard.py b/spynnaker/pyNN/models/neuron/implementations/meanfield_impl_standard.py index d8f1cd153d2..6aa2f5c4cd9 100644 --- a/spynnaker/pyNN/models/neuron/implementations/meanfield_impl_standard.py +++ b/spynnaker/pyNN/models/neuron/implementations/meanfield_impl_standard.py @@ -48,24 +48,31 @@ class MeanfieldImplStandard(AbstractNeuronImpl): ] # _RECORDABLES = ["Ve", "gsyn_exc", "gsyn_inh"] - _RECORDABLES = ["Ve", "Vi", "sV", "muGn", "TvN", "Vthre", - "Fout_th", "err_func", "gsyn_exc", "gsyn_inh"] + #_RECORDABLES = ["Ve", "Vi", "sV", "muGn", "TvN", "Vthre", + # "Fout_th", "err_func", "gsyn_exc", "gsyn_inh"] + _RECORDABLES = ["Ve", "Vi", "Fout_th", "gsyn_exc", "gsyn_inh"] # _RECORDABLE_DATA_TYPES = { # "Ve": DataType.S1615, # "gsyn_exc": DataType.S1615, # "gsyn_inh": DataType.S1615 # } + #_RECORDABLE_DATA_TYPES = { + # "Ve": DataType.S1615, + # "Vi": DataType.S1615, + # "sV": DataType.S1615, + # "muGn": DataType.S1615, + # "TvN": DataType.S1615, + # "Vthre": DataType.S1615, + # "Fout_th": DataType.S1615, + # "err_func": DataType.S1615, + # "gsyn_exc": DataType.S1615, + # "gsyn_inh": DataType.S1615 + #} _RECORDABLE_DATA_TYPES = { "Ve": DataType.S1615, "Vi": DataType.S1615, - #"muV": DataType.S1615, - "sV": DataType.S1615, - "muGn": DataType.S1615, - "TvN": DataType.S1615, - "Vthre": DataType.S1615, "Fout_th": DataType.S1615, - "err_func": DataType.S1615, "gsyn_exc": DataType.S1615, "gsyn_inh": DataType.S1615 } @@ -75,16 +82,22 @@ class MeanfieldImplStandard(AbstractNeuronImpl): # 'gsyn_exc': "uS", # 'gsyn_inh': "uS" # } - _RECORDABLE_UNITS = { +# _RECORDABLE_UNITS = { +# 'Ve': 'mV', +# 'Vi': 'mV', +# 'sV': "uS", +# 'muGn':"uS", +# 'TvN': 'mV', +# 'Vthre': "uS", +# 'Fout_th': "uS", +# 'err_func': 'mV', +# 'gsyn_exc': "uS", +# 'gsyn_inh': "uS" +# } + _RECORDABLE_UNITS = { 'Ve': 'mV', - 'Vi': "mV", - #'muV': "uS", - 'sV': "uS", - 'muGn':"uS", - 'TvN': 'mV', - 'Vthre': "uS", + 'Vi': 'mV', 'Fout_th': "uS", - 'err_func': 'mV', 'gsyn_exc': "uS", 'gsyn_inh': "uS" } diff --git a/spynnaker/pyNN/models/neuron/neuron_models/meanfield_model_eitn.py b/spynnaker/pyNN/models/neuron/neuron_models/meanfield_model_eitn.py index 7caa8cde165..1aa010e946d 100644 --- a/spynnaker/pyNN/models/neuron/neuron_models/meanfield_model_eitn.py +++ b/spynnaker/pyNN/models/neuron/neuron_models/meanfield_model_eitn.py @@ -54,7 +54,7 @@ class MeanfieldModelEitn(AbstractNeuronModel): """ __slots__ = [ "_nbr", "_a", "_b", "_tauw", "_Trefrac", "_Vreset", "_delta_v", - "_ampnoise", "_Timescale_inv", "_Ve_init", "_Vi_init", + "_ampnoise", "_Timescale_inv", "_Ve_init", "_Vi_init" ] def __init__(self, nbr, a, b, tauw, @@ -134,7 +134,6 @@ def add_parameters(self, parameters): def add_state_variables(self, state_variables): state_variables[VE] = self._Ve_init state_variables[VI] = self._Vi_init - #state_variables[U] = self.__u_init @overrides(AbstractStandardNeuronComponent.get_units) def get_units(self, variable): From be1be0c98f12ad73ca8e96c114de5f4b9796fc36 Mon Sep 17 00:00:00 2001 From: Garandel Date: Thu, 21 Oct 2021 14:23:18 +0000 Subject: [PATCH 20/44] modified: ../../src/meanfield/implementations/meanfield_impl_standard.h modified: ../../src/meanfield/models/meanfield_model_impl.c modified: ../../../spynnaker/pyNN/models/neuron/implementations/meanfield_impl_standard.py modified: ../../../spynnaker/pyNN/models/neuron/neuron_models/meanfield_model_eitn.py modified: ../../../spynnaker8/extra_models/__init__.py OK problem don't comming from printing data but I guess from creating them. I will change some C code in meanfield_impl_standard.h PBL is like if Ve and g_syn are ok to be create but not Vi and Fout_th for a 5 vars recorded --- .../implementations/meanfield_impl_standard.h | 2 +- .../meanfield/models/meanfield_model_impl.c | 16 ++++---- .../meanfield_impl_standard.py | 39 +------------------ .../neuron_models/meanfield_model_eitn.py | 2 +- spynnaker8/extra_models/__init__.py | 1 + 5 files changed, 12 insertions(+), 48 deletions(-) diff --git a/neural_modelling/src/meanfield/implementations/meanfield_impl_standard.h b/neural_modelling/src/meanfield/implementations/meanfield_impl_standard.h index 9d843e0065a..50b9bdde661 100644 --- a/neural_modelling/src/meanfield/implementations/meanfield_impl_standard.h +++ b/neural_modelling/src/meanfield/implementations/meanfield_impl_standard.h @@ -146,7 +146,7 @@ static bool meanfield_impl_initialise(uint32_t n_meanfields) { // Allocate DTCM for mathsbox array and copy block of data if (sizeof(mathsbox_t)) { - mathsbox_array = spin1_malloc(n_meanfields * sizeof(config_t)); + mathsbox_array = spin1_malloc(n_meanfields * sizeof(mathsbox_t)); if (mathsbox_array == NULL) { log_error("Unable to allocate mathsbox array - Out of DTCM"); return false; diff --git a/neural_modelling/src/meanfield/models/meanfield_model_impl.c b/neural_modelling/src/meanfield/models/meanfield_model_impl.c index 902a299db2b..67c3ee054e0 100644 --- a/neural_modelling/src/meanfield/models/meanfield_model_impl.c +++ b/neural_modelling/src/meanfield/models/meanfield_model_impl.c @@ -244,9 +244,7 @@ void TF(REAL Ve, REAL Vi, meanfield_t *meanfield, config_t *restrict config, get_fluct_regime_varsup(Ve, Vi, config); threshold_func(config); - if (config->sVsV += ACS_DBL_TINY; - } + limit = REAL_CONST(0.5)*(config->Gl/(config->TvN * config->Cm)); /* @@ -254,7 +252,9 @@ void TF(REAL Ve, REAL Vi, meanfield_t *meanfield, config_t *restrict config, argument = (config->Vthre - config->muV)/sqrtk(REAL_CONST(2.))/config->sV; */ - + if (config->sVsV += ACS_DBL_TINY; + } argument = (config->Vthre - config->muV)/(REAL_CONST(1.4142137))/config->sV; // config->Fout_th = error_function(factor, argument, mathsbox); @@ -277,11 +277,11 @@ void RK2_midpoint_MF(REAL h, meanfield_t *meanfield, config_t *restrict config, on the user computer before send it to the DTCM. */ REAL lastVe = meanfield->Ve; - REAL lastVi = meanfield->Vi; + REAL lastVi = 1.;//meanfield->Vi; - if (lastVi < ACS_DBL_TINY){ + /*if (lastVi < ACS_DBL_TINY){ lastVi += ACS_DBL_TINY; - } + }*/ REAL T_inv = meanfield->Timescale_inv; @@ -299,7 +299,7 @@ on the user computer before send it to the DTCM. meanfield->Ve += lastVe + (REAL_HALF(lastTF - lastVe) * (REAL_CONST(2.0)-h) * h); meanfield->Ve = meanfield->Ve * T_inv; - meanfield->Vi += lastVi; + meanfield->Vi += lastVi*2; //meanfield->Vi += T_inv*(lastVi + (REAL_HALF(lastTF - lastVi) * (REAL_CONST(2.0)-h) * h)); //meanfield->Vi = meanfield->Vi * T_inv; diff --git a/spynnaker/pyNN/models/neuron/implementations/meanfield_impl_standard.py b/spynnaker/pyNN/models/neuron/implementations/meanfield_impl_standard.py index 6aa2f5c4cd9..78de61be3d1 100644 --- a/spynnaker/pyNN/models/neuron/implementations/meanfield_impl_standard.py +++ b/spynnaker/pyNN/models/neuron/implementations/meanfield_impl_standard.py @@ -47,28 +47,8 @@ class MeanfieldImplStandard(AbstractNeuronImpl): "__n_steps_per_timestep" ] - # _RECORDABLES = ["Ve", "gsyn_exc", "gsyn_inh"] - #_RECORDABLES = ["Ve", "Vi", "sV", "muGn", "TvN", "Vthre", - # "Fout_th", "err_func", "gsyn_exc", "gsyn_inh"] _RECORDABLES = ["Ve", "Vi", "Fout_th", "gsyn_exc", "gsyn_inh"] - # _RECORDABLE_DATA_TYPES = { - # "Ve": DataType.S1615, - # "gsyn_exc": DataType.S1615, - # "gsyn_inh": DataType.S1615 - # } - #_RECORDABLE_DATA_TYPES = { - # "Ve": DataType.S1615, - # "Vi": DataType.S1615, - # "sV": DataType.S1615, - # "muGn": DataType.S1615, - # "TvN": DataType.S1615, - # "Vthre": DataType.S1615, - # "Fout_th": DataType.S1615, - # "err_func": DataType.S1615, - # "gsyn_exc": DataType.S1615, - # "gsyn_inh": DataType.S1615 - #} _RECORDABLE_DATA_TYPES = { "Ve": DataType.S1615, "Vi": DataType.S1615, @@ -77,24 +57,7 @@ class MeanfieldImplStandard(AbstractNeuronImpl): "gsyn_inh": DataType.S1615 } - # _RECORDABLE_UNITS = { - # 'Ve': 'mV', - # 'gsyn_exc': "uS", - # 'gsyn_inh': "uS" - # } -# _RECORDABLE_UNITS = { -# 'Ve': 'mV', -# 'Vi': 'mV', -# 'sV': "uS", -# 'muGn':"uS", -# 'TvN': 'mV', -# 'Vthre': "uS", -# 'Fout_th': "uS", -# 'err_func': 'mV', -# 'gsyn_exc': "uS", -# 'gsyn_inh': "uS" -# } - _RECORDABLE_UNITS = { + _RECORDABLE_UNITS = { 'Ve': 'mV', 'Vi': 'mV', 'Fout_th': "uS", diff --git a/spynnaker/pyNN/models/neuron/neuron_models/meanfield_model_eitn.py b/spynnaker/pyNN/models/neuron/neuron_models/meanfield_model_eitn.py index 1aa010e946d..107af533fd1 100644 --- a/spynnaker/pyNN/models/neuron/neuron_models/meanfield_model_eitn.py +++ b/spynnaker/pyNN/models/neuron/neuron_models/meanfield_model_eitn.py @@ -50,7 +50,7 @@ class MeanfieldModelEitn(AbstractNeuronModel): - """ Model of meanfield due to Destehexe et al + """ Model of meanfield due to A.Destehexe et al """ __slots__ = [ "_nbr", "_a", "_b", "_tauw", "_Trefrac", "_Vreset", "_delta_v", diff --git a/spynnaker8/extra_models/__init__.py b/spynnaker8/extra_models/__init__.py index b5bff8865a9..ad7b02682b8 100644 --- a/spynnaker8/extra_models/__init__.py +++ b/spynnaker8/extra_models/__init__.py @@ -36,6 +36,7 @@ # sPyNNaker 8 models 'IFCurDelta', 'IFCurrExpCa2Adaptive', 'IFCondExpStoc', 'Izhikevich_cond', 'IF_curr_dual_exp', 'IF_curr_exp_sEMD', + 'Meanfield', # sPyNNaker 8 plastic stuff 'WeightDependenceAdditiveTriplet', From 565bcd5b854fb64233c0000f5ac482d2fdff21bc Mon Sep 17 00:00:00 2001 From: Garandel Date: Thu, 21 Oct 2021 15:51:58 +0000 Subject: [PATCH 21/44] modified: ../../src/meanfield/models/meanfield_model_impl.c Need to add Vi really to tyhe implementation and so to meanfield_model_impl.h and .c and to meanfield_model.h so if need comme back here --- .../src/meanfield/models/meanfield_model_impl.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/neural_modelling/src/meanfield/models/meanfield_model_impl.c b/neural_modelling/src/meanfield/models/meanfield_model_impl.c index 67c3ee054e0..c7c371d6a80 100644 --- a/neural_modelling/src/meanfield/models/meanfield_model_impl.c +++ b/neural_modelling/src/meanfield/models/meanfield_model_impl.c @@ -285,7 +285,7 @@ on the user computer before send it to the DTCM. REAL T_inv = meanfield->Timescale_inv; - TF(1., lastVi, meanfield, config, mathsbox); + TF(lastVe, lastVi, meanfield, config, mathsbox); REAL lastTF = config->Fout_th; //configVe stand for TF1 i.e TF for exitatory pop. SO configVi is for TF2 //In fact no configVe and configVi just config, all in the same file. @@ -299,9 +299,9 @@ on the user computer before send it to the DTCM. meanfield->Ve += lastVe + (REAL_HALF(lastTF - lastVe) * (REAL_CONST(2.0)-h) * h); meanfield->Ve = meanfield->Ve * T_inv; - meanfield->Vi += lastVi*2; - //meanfield->Vi += T_inv*(lastVi + (REAL_HALF(lastTF - lastVi) * (REAL_CONST(2.0)-h) * h)); - //meanfield->Vi = meanfield->Vi * T_inv; + + meanfield->Vi += T_inv*(lastVi + (REAL_HALF(lastTF - lastVi) * (REAL_CONST(2.0)-h) * h)); + meanfield->Vi = meanfield->Vi * T_inv; } From a1b4baf0747323f56c8c140bc02478e8de30bcdc Mon Sep 17 00:00:00 2001 From: Garandel Date: Thu, 21 Oct 2021 16:08:41 +0000 Subject: [PATCH 22/44] modified: ../../src/meanfield/implementations/meanfield_impl_standard.h modified: ../../src/meanfield/models/meanfield_model.h modified: ../../src/meanfield/models/meanfield_model_impl.c Ok that working a priori, it's not the most beautiful but it's working Just one comment is : the numbers between Ve and Vi are not treat as the same, don't understadn why?? --- .../implementations/meanfield_impl_standard.h | 18 +++++++++++------- .../src/meanfield/models/meanfield_model.h | 3 ++- .../meanfield/models/meanfield_model_impl.c | 6 +++++- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/neural_modelling/src/meanfield/implementations/meanfield_impl_standard.h b/neural_modelling/src/meanfield/implementations/meanfield_impl_standard.h index 50b9bdde661..11e99d80682 100644 --- a/neural_modelling/src/meanfield/implementations/meanfield_impl_standard.h +++ b/neural_modelling/src/meanfield/implementations/meanfield_impl_standard.h @@ -40,11 +40,12 @@ //! Indices for recording of words enum word_recording_indices { //! V (somatic potential) recording index - V_RECORDING_INDEX = 0, + VE_RECORDING_INDEX = 0, + VI_RECORDING_INDEX = 1, //! Gsyn_exc (excitatory synaptic conductance/current) recording index - GSYN_EXC_RECORDING_INDEX = 1, + GSYN_EXC_RECORDING_INDEX = 2, //! Gsyn_inh (excitatory synaptic conductance/current) recording index - GSYN_INH_RECORDING_INDEX = 2, + GSYN_INH_RECORDING_INDEX = 3, //! Number of recorded word-sized state variables N_RECORDED_VARS = 5 }; @@ -336,7 +337,8 @@ static void neuron_impl_do_timestep_update( // and because the index doesn't actually matter for (uint32_t i_step = n_steps_per_timestep; i_step > 0; i_step--) { // Get the voltage->firing rate - state_t firing_rate = meanfield_model_get_firing_rate(this_meanfield); + state_t firing_rate_Ve = meanfield_model_get_firing_rate_Ve(this_meanfield); + state_t firing_rate_Vi = meanfield_model_get_firing_rate_Vi(this_meanfield); // Get the exc and inh values from the synapses input_t exc_values[NUM_EXCITATORY_RECEPTORS]; @@ -366,7 +368,9 @@ static void neuron_impl_do_timestep_update( // Do recording if on the first step if (i_step == n_steps_per_timestep) { neuron_recording_record_accum( - V_RECORDING_INDEX, meanfield_index, firing_rate); + VE_RECORDING_INDEX, meanfield_index, firing_rate_Ve); + neuron_recording_record_accum( + VI_RECORDING_INDEX, meanfield_index, firing_rate_Vi); neuron_recording_record_accum( GSYN_EXC_RECORDING_INDEX, meanfield_index, total_exc); neuron_recording_record_accum( @@ -375,9 +379,9 @@ static void neuron_impl_do_timestep_update( // Call functions to convert exc_input and inh_input to current input_type_convert_excitatory_input_to_current( - exc_input_values, input_types, firing_rate); + exc_input_values, input_types, firing_rate_Ve); input_type_convert_inhibitory_input_to_current( - inh_input_values, input_types, firing_rate); + inh_input_values, input_types, firing_rate_Vi); // input_t external_bias += additional_input_get_input_value_as_current( // additional_inputs, firing_rate); diff --git a/neural_modelling/src/meanfield/models/meanfield_model.h b/neural_modelling/src/meanfield/models/meanfield_model.h index 7c65d7c4160..6c7e97b7ccc 100644 --- a/neural_modelling/src/meanfield/models/meanfield_model.h +++ b/neural_modelling/src/meanfield/models/meanfield_model.h @@ -90,7 +90,8 @@ void neuron_model_has_spiked(meanfield_t *restrict meanfield); //! all the parameters for a specific neuron //! \return the membrane voltage for a given neuron with the neuron //! parameters specified in neuron -state_t meanfield_model_get_firing_rate(const meanfield_t *meanfield); +state_t meanfield_model_get_firing_rate_Ve(const meanfield_t *meanfield); +state_t meanfield_model_get_firing_rate_Vi(const meanfield_t *meanfield); //! \brief printout of state variables i.e. those values that might change //! \param[in] neuron: a pointer to a neuron parameter struct which contains all diff --git a/neural_modelling/src/meanfield/models/meanfield_model_impl.c b/neural_modelling/src/meanfield/models/meanfield_model_impl.c index c7c371d6a80..53d5239c0bc 100644 --- a/neural_modelling/src/meanfield/models/meanfield_model_impl.c +++ b/neural_modelling/src/meanfield/models/meanfield_model_impl.c @@ -396,10 +396,14 @@ void neuron_model_has_spiked(meanfield_t *restrict meanfield) { } //change name neuron -> meanfield and membrane -> rate -state_t meanfield_model_get_firing_rate(const meanfield_t *meanfield) { +state_t meanfield_model_get_firing_rate_Ve(const meanfield_t *meanfield) { return meanfield->Ve; } +state_t meanfield_model_get_firing_rate_Vi(const meanfield_t *meanfield) { + return meanfield->Vi; +} + void meanfield_model_print_state_variables(const meanfield_t *meanfield) { log_debug("Ve = %11.4k ", meanfield->Ve); log_debug("Vi = %11.4k ", meanfield->Vi); From 3fd336ba75afa8a7c43cf5686000eda927e71ca6 Mon Sep 17 00:00:00 2001 From: Garandel Date: Fri, 22 Oct 2021 11:43:11 +0000 Subject: [PATCH 23/44] modified: src/meanfield/implementations/meanfield_impl_standard.h modified: src/meanfield/models/meanfield_model.h modified: src/meanfield/models/meanfield_model_impl.c a priori that's work for Ve, Vi and Fout_th ->will add an other TF() and so an other threshold_function() in order to have a MF --- .../implementations/meanfield_impl_standard.h | 14 ++++++++------ .../src/meanfield/models/meanfield_model.h | 1 + .../src/meanfield/models/meanfield_model_impl.c | 13 +++++++++---- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/neural_modelling/src/meanfield/implementations/meanfield_impl_standard.h b/neural_modelling/src/meanfield/implementations/meanfield_impl_standard.h index 11e99d80682..7336ff791b5 100644 --- a/neural_modelling/src/meanfield/implementations/meanfield_impl_standard.h +++ b/neural_modelling/src/meanfield/implementations/meanfield_impl_standard.h @@ -42,10 +42,11 @@ enum word_recording_indices { //! V (somatic potential) recording index VE_RECORDING_INDEX = 0, VI_RECORDING_INDEX = 1, + FOUT_TH_RECORDING_INDEX = 2, //! Gsyn_exc (excitatory synaptic conductance/current) recording index - GSYN_EXC_RECORDING_INDEX = 2, + GSYN_EXC_RECORDING_INDEX = 3, //! Gsyn_inh (excitatory synaptic conductance/current) recording index - GSYN_INH_RECORDING_INDEX = 3, + GSYN_INH_RECORDING_INDEX = 4, //! Number of recorded word-sized state variables N_RECORDED_VARS = 5 }; @@ -339,6 +340,8 @@ static void neuron_impl_do_timestep_update( // Get the voltage->firing rate state_t firing_rate_Ve = meanfield_model_get_firing_rate_Ve(this_meanfield); state_t firing_rate_Vi = meanfield_model_get_firing_rate_Vi(this_meanfield); + + state_t Fout_th = meanfield_model_get_Fout_th(config_types); // Get the exc and inh values from the synapses input_t exc_values[NUM_EXCITATORY_RECEPTORS]; @@ -365,12 +368,14 @@ static void neuron_impl_do_timestep_update( total_inh += inh_input_values[i]; } - // Do recording if on the first step + // Do recording if on the first step if (i_step == n_steps_per_timestep) { neuron_recording_record_accum( VE_RECORDING_INDEX, meanfield_index, firing_rate_Ve); neuron_recording_record_accum( VI_RECORDING_INDEX, meanfield_index, firing_rate_Vi); + neuron_recording_record_accum( + FOUT_TH_RECORDING_INDEX, meanfield_index, Fout_th); neuron_recording_record_accum( GSYN_EXC_RECORDING_INDEX, meanfield_index, total_exc); neuron_recording_record_accum( @@ -390,9 +395,6 @@ static void neuron_impl_do_timestep_update( state_t result = meanfield_model_state_update( this_meanfield, config_types, mathsbox_types); - //reinitialise Fout_th - config_types->Fout_th = 0.0; // I don't understand what this does - // determine if a spike should occur bool spike_now = threshold_type_is_above_threshold(result, the_threshold_type); diff --git a/neural_modelling/src/meanfield/models/meanfield_model.h b/neural_modelling/src/meanfield/models/meanfield_model.h index 6c7e97b7ccc..bec50f1e10b 100644 --- a/neural_modelling/src/meanfield/models/meanfield_model.h +++ b/neural_modelling/src/meanfield/models/meanfield_model.h @@ -92,6 +92,7 @@ void neuron_model_has_spiked(meanfield_t *restrict meanfield); //! parameters specified in neuron state_t meanfield_model_get_firing_rate_Ve(const meanfield_t *meanfield); state_t meanfield_model_get_firing_rate_Vi(const meanfield_t *meanfield); +state_t meanfield_model_get_Fout_th(const config_t *config); //! \brief printout of state variables i.e. those values that might change //! \param[in] neuron: a pointer to a neuron parameter struct which contains all diff --git a/neural_modelling/src/meanfield/models/meanfield_model_impl.c b/neural_modelling/src/meanfield/models/meanfield_model_impl.c index 53d5239c0bc..6d5092a118e 100644 --- a/neural_modelling/src/meanfield/models/meanfield_model_impl.c +++ b/neural_modelling/src/meanfield/models/meanfield_model_impl.c @@ -76,7 +76,7 @@ void error_function( REAL x, REAL factor, mathsbox_t *restrict mathsbox){ //REAL Pi = 3.1415927;// here was a k REAL two_over_sqrt_Pi = REAL_CONST(1.128379167); //APPROXIMATION REAL Erfc = mathsbox->err_func; - for(t=0; t==x; t+=dt){ + for(t=0; t<=x; t+=dt){ //Erfc += dt; //test otherwise ITCM overload //Erfc += factor*(2/sqrtk(Pi))*expk(-(t*t)); // the real one overflowed ITCM Erfc += factor*two_over_sqrt_Pi*expk(-(t*t)); //working like this one @@ -259,7 +259,7 @@ void TF(REAL Ve, REAL Vi, meanfield_t *meanfield, config_t *restrict config, // config->Fout_th = error_function(factor, argument, mathsbox); error_function(limit, argument, mathsbox); - config->Fout_th = (HALF*config->Gl) * mathsbox->err_func / (config->Cm*config->TvN) ;// REAL ONE + config->Fout_th = (HALF*config->Gl) * mathsbox->err_func / (config->Cm*config->TvN);// REAL ONE //config->Fout_th = mathsbox->err_func ; //TEST @@ -277,7 +277,7 @@ void RK2_midpoint_MF(REAL h, meanfield_t *meanfield, config_t *restrict config, on the user computer before send it to the DTCM. */ REAL lastVe = meanfield->Ve; - REAL lastVi = 1.;//meanfield->Vi; + REAL lastVi = meanfield->Vi; /*if (lastVi < ACS_DBL_TINY){ lastVi += ACS_DBL_TINY; @@ -300,7 +300,7 @@ on the user computer before send it to the DTCM. meanfield->Ve = meanfield->Ve * T_inv; - meanfield->Vi += T_inv*(lastVi + (REAL_HALF(lastTF - lastVi) * (REAL_CONST(2.0)-h) * h)); + meanfield->Vi += lastVi + (REAL_HALF(lastTF - lastVi) * (REAL_CONST(2.0)-h) * h); meanfield->Vi = meanfield->Vi * T_inv; @@ -404,6 +404,11 @@ state_t meanfield_model_get_firing_rate_Vi(const meanfield_t *meanfield) { return meanfield->Vi; } +state_t meanfield_model_get_Fout_th(const config_t *config){ + return config->Fout_th; +} + + void meanfield_model_print_state_variables(const meanfield_t *meanfield) { log_debug("Ve = %11.4k ", meanfield->Ve); log_debug("Vi = %11.4k ", meanfield->Vi); From 09e51a1d3d4b606e2c0237ed686a28c51546689e Mon Sep 17 00:00:00 2001 From: Garandel Date: Fri, 22 Oct 2021 13:29:51 +0000 Subject: [PATCH 24/44] modified: ../../src/meanfield/models/meanfield_model_impl.c before add config Vi --- .../meanfield/models/meanfield_model_impl.c | 37 ++++--------------- 1 file changed, 8 insertions(+), 29 deletions(-) diff --git a/neural_modelling/src/meanfield/models/meanfield_model_impl.c b/neural_modelling/src/meanfield/models/meanfield_model_impl.c index 6d5092a118e..df62caa1798 100644 --- a/neural_modelling/src/meanfield/models/meanfield_model_impl.c +++ b/neural_modelling/src/meanfield/models/meanfield_model_impl.c @@ -77,16 +77,12 @@ void error_function( REAL x, REAL factor, mathsbox_t *restrict mathsbox){ REAL two_over_sqrt_Pi = REAL_CONST(1.128379167); //APPROXIMATION REAL Erfc = mathsbox->err_func; for(t=0; t<=x; t+=dt){ - //Erfc += dt; //test otherwise ITCM overload //Erfc += factor*(2/sqrtk(Pi))*expk(-(t*t)); // the real one overflowed ITCM Erfc += factor*two_over_sqrt_Pi*expk(-(t*t)); //working like this one - //Erfc += factor+t*t;//fake one working } mathsbox->err_func = Erfc; - //return Erfc; - } @@ -149,10 +145,8 @@ void threshold_func(config_t *restrict config) } -// REAL ONE get_fluct_regime_varsup void get_fluct_regime_varsup(REAL Ve, REAL Vi, config_t *restrict params) { - //takes 880 bytes overflowed ITCM REAL Fe; REAL Fi; @@ -217,18 +211,13 @@ void get_fluct_regime_varsup(REAL Ve, REAL Vi, config_t *restrict params) params->TvN = Tv*params->Gl/params->Cm; - //return params->muV;//, sV+1e-12, muGn, TvN } -//END of the REAL get_fluct_regime_varsup void TF(REAL Ve, REAL Vi, meanfield_t *meanfield, config_t *restrict config, mathsbox_t *restrict mathsbox){ -// argument are fe, fi and pseq_params -// problem is to implement it with params and instruction coming from -// DTCM and ITCM. -// when get_fluct_regime_varsup is ON takes 1360 bytes overflowed ITCM +//PUT comments HERE!!! REAL limit; @@ -244,8 +233,6 @@ void TF(REAL Ve, REAL Vi, meanfield_t *meanfield, config_t *restrict config, get_fluct_regime_varsup(Ve, Vi, config); threshold_func(config); - - limit = REAL_CONST(0.5)*(config->Gl/(config->TvN * config->Cm)); /* normalement sqrt: @@ -257,8 +244,12 @@ void TF(REAL Ve, REAL Vi, meanfield_t *meanfield, config_t *restrict config, } argument = (config->Vthre - config->muV)/(REAL_CONST(1.4142137))/config->sV; -// config->Fout_th = error_function(factor, argument, mathsbox); error_function(limit, argument, mathsbox); + + if (config->P0 == 0.){ + mathsbox->err_func = 1; + } + config->Fout_th = (HALF*config->Gl) * mathsbox->err_func / (config->Cm*config->TvN);// REAL ONE //config->Fout_th = mathsbox->err_func ; //TEST @@ -267,22 +258,15 @@ void TF(REAL Ve, REAL Vi, meanfield_t *meanfield, config_t *restrict config, config->Fout_th += ACS_DBL_TINY; } - //return config->Fout_th; } void RK2_midpoint_MF(REAL h, meanfield_t *meanfield, config_t *restrict config, mathsbox_t *restrict mathsbox) { -/* need to input T_inv time scale where the 1/T will be done (and rounding) -on the user computer before send it to the DTCM. -*/ + REAL lastVe = meanfield->Ve; REAL lastVi = meanfield->Vi; - - /*if (lastVi < ACS_DBL_TINY){ - lastVi += ACS_DBL_TINY; - }*/ - + REAL T_inv = meanfield->Timescale_inv; TF(lastVe, lastVi, meanfield, config, mathsbox); @@ -291,11 +275,6 @@ on the user computer before send it to the DTCM. //In fact no configVe and configVi just config, all in the same file. - /*meanfield->Ve += lastVe\ - + REAL_HALF(TF(lastVe,1,meanfield, config, mathsbox) - lastVe)\ - *(REAL_CONST(2.0)-h)*h; - */ - meanfield->Ve += lastVe + (REAL_HALF(lastTF - lastVe) * (REAL_CONST(2.0)-h) * h); meanfield->Ve = meanfield->Ve * T_inv; From 4e39dd7f1efbe0ea425fda13ac6f50d7fa4824ea Mon Sep 17 00:00:00 2001 From: Garandel Date: Mon, 25 Oct 2021 11:47:49 +0000 Subject: [PATCH 25/44] new file: Vthre_params.h modified: config.h modified: meanfield_model.h modified: meanfield_model_impl.c Add in the c code the inhibitory contribution of the MF and so the differenciation btw Exc and Inh. Names of some variables and params will be change in order to don't induce misunderstanding. --- .../src/meanfield/models/Vthre_params.h | 23 ++++ .../src/meanfield/models/config.h | 36 ++---- .../src/meanfield/models/meanfield_model.h | 4 + .../meanfield/models/meanfield_model_impl.c | 115 +++++++++++------- 4 files changed, 113 insertions(+), 65 deletions(-) create mode 100644 neural_modelling/src/meanfield/models/Vthre_params.h diff --git a/neural_modelling/src/meanfield/models/Vthre_params.h b/neural_modelling/src/meanfield/models/Vthre_params.h new file mode 100644 index 00000000000..6e28cf6bafb --- /dev/null +++ b/neural_modelling/src/meanfield/models/Vthre_params.h @@ -0,0 +1,23 @@ +#ifndef _VTHRE_PARAMS_H_ +#define _VTHRE_PARAMS_H_ + +#include "../../meanfield/models/meanfield_model.h" + + +typedef struct Vthre_params_t { + // nominally 'fixed' parameters + + REAL P0; + REAL P1; + REAL P2; + REAL P3; + REAL P4; + REAL P5; + REAL P6; + REAL P7; + REAL P8; + REAL P9; + REAL P10; + + +#endif \ No newline at end of file diff --git a/neural_modelling/src/meanfield/models/config.h b/neural_modelling/src/meanfield/models/config.h index 89614141f09..f3fa1807386 100644 --- a/neural_modelling/src/meanfield/models/config.h +++ b/neural_modelling/src/meanfield/models/config.h @@ -25,41 +25,29 @@ typedef struct config_t { REAL Gl; REAL Cm; REAL El; - - REAL P0; - REAL P1; - REAL P2; - REAL P3; - REAL P4; - REAL P5; - REAL P6; - REAL P7; - REAL P8; - REAL P9; - REAL P10; // Variable-state parameters //REAL fe; //REAL fi; - REAL muV;//:=0.0; + REAL muV; REAL muV0; - //muV0 = -60e-3; - REAL DmuV0;// = 10e-3; - REAL sV;//=0.0; - REAL sV0;// = 4e-3; - REAL DsV0;// = 6e-3; + REAL DmuV0; + + REAL sV; + REAL sV0; + REAL DsV0; - REAL muGn;//=0.0; + REAL muGn; - REAL TvN;//=0.0; - REAL TvN0;// = 0.5; - REAL DTvN0;// = 1.; + REAL TvN; + REAL TvN0; + REAL DTvN0; - REAL Vthre;//=0.0; + REAL Vthre; - REAL Fout_th;//=0.0; + REAL Fout_th; } config_t; /* diff --git a/neural_modelling/src/meanfield/models/meanfield_model.h b/neural_modelling/src/meanfield/models/meanfield_model.h index bec50f1e10b..8a4bb14e7fb 100644 --- a/neural_modelling/src/meanfield/models/meanfield_model.h +++ b/neural_modelling/src/meanfield/models/meanfield_model.h @@ -37,6 +37,10 @@ struct config_t; typedef struct config_t config_t; typedef struct config_t* config_pointer_t; +struct Vthre_params_t; +typedef struct Vthre_params_t Vthre_params_t; +typedef struct Vthre_params_t* Vthre_params_pointer_t; + struct mathsbox_t; typedef struct mathsbox_t mathsbox_t; typedef struct mathsbox_t* mathsbox_pointer_t; diff --git a/neural_modelling/src/meanfield/models/meanfield_model_impl.c b/neural_modelling/src/meanfield/models/meanfield_model_impl.c index df62caa1798..a733248630d 100644 --- a/neural_modelling/src/meanfield/models/meanfield_model_impl.c +++ b/neural_modelling/src/meanfield/models/meanfield_model_impl.c @@ -86,7 +86,7 @@ void error_function( REAL x, REAL factor, mathsbox_t *restrict mathsbox){ } -void threshold_func(config_t *restrict config) +void threshold_func(config_t *restrict config, Vthre_params_t *restrict Vparams) { /* setting by default to True the square @@ -113,17 +113,17 @@ void threshold_func(config_t *restrict config) REAL Vthre = config->Vthre;//=0.; //REAL Fout_th = config->Fout_th;//=0.; - REAL P0 = config->P0; - REAL P1 = config->P1; - REAL P2 = config->P2; - REAL P3 = config->P3; - //REAL P4 = config->P4; - REAL P5 = config->P5; - REAL P6 = config->P6; - REAL P7 = config->P7; - REAL P8 = config->P8; - REAL P9 = config->P9; - REAL P10 = config->P10; + REAL P0 = Vparams->P0; + REAL P1 = Vparams->P1; + REAL P2 = Vparams->P2; + REAL P3 = Vparams->P3; + REAL P4 = Vparams->P4; + REAL P5 = Vparams->P5; + REAL P6 = Vparams->P6; + REAL P7 = Vparams->P7; + REAL P8 = Vparams->P8; + REAL P9 = Vparams->P9; + REAL P10 = Vparams->P10; @@ -145,7 +145,7 @@ void threshold_func(config_t *restrict config) } -void get_fluct_regime_varsup(REAL Ve, REAL Vi, config_t *restrict params) +void get_fluct_regime_varsup(REAL Ve, REAL Vi, config_t *restrict config) { REAL Fe; @@ -153,31 +153,51 @@ void get_fluct_regime_varsup(REAL Ve, REAL Vi, config_t *restrict params) REAL muGe, muGi, muG; REAL Ue, Ui; REAL Tm, Tv; + + REAL gei = config->gei; + REAL pconnec = config->pconnec; + REAL Ntot = config->Ntot; + REAL Qe = config->Qe; + REAL Qi = config->Qi; + REAL Te = config->Te; + REAL Ti = config->Ti; + REAL Gl = config->Gl; + REAL El = config->El; + REAL Ei = config->Ei; + REAL Ee = config->Ee; + REAL Cm = config->Cm; + + REAL muV = config->muV; + REAL muGn = config->muGn; + REAL sV = config->sV; + REAL TvN = config->TvN; + + // here TOTAL (sum over synapses) excitatory and inhibitory input - Fe = Ve * (REAL_CONST(1.)-params->gei)*params->pconnec*params->Ntot; // default is 1 !! - Fi = Vi * params->gei*params->pconnec*params->Ntot; + Fe = Ve * (REAL_CONST(1.)-gei)*pconnec*Ntot; // default is 1 !! + Fi = Vi * gei*pconnec*Ntot; - muGe = params->Qe*params->Te*Ve; - muGi = params->Qi*params->Ti*Vi; + muGe = Qe*Te*Ve; + muGi = Qi*Ti*Vi; - muG = params->Gl+muGe+muGi; + muG = Gl+muGe+muGi; if (muG < ACS_DBL_TINY){ muG += ACS_DBL_TINY; } - params->muV = (muGe*params->Ee+muGi*params->Ei+params->Gl*params->El)/muG; + muV = (muGe*Ee + muGi*Ei + Gl*El)/muG; - params->muGn = muG/params->Gl; + muGn = muG/Gl; - Tm = params->Cm/muG; + Tm = Cm/muG; - Ue = params->Qe/muG*(params->Ee-params->muV); - Ui = params->Qi/muG*(params->Ei-params->muV); + Ue = Qe/muG*(Ee-muV); + Ui = Qi/muG*(Ei-muV); /* @@ -189,8 +209,8 @@ void get_fluct_regime_varsup(REAL Ve, REAL Vi, config_t *restrict params) */ - params->sV = Fe*(Ue*params->Te)*(Ue*params->Te)/REAL_CONST(2.)/(params->Te+Tm)\ - + Fi*(params->Ti*Ui)*(params->Ti*Ui)/REAL_CONST(2.)/(params->Ti+Tm); + sV = Fe*(Ue*Te)*(Ue*Te)/REAL_CONST(2.)/(Te+Tm)\ + + Fi*(Ti*Ui)*(Ti*Ui)/REAL_CONST(2.)/(Ti+Tm); if (FeTe)*(Ue*params->Te) + Fi*(params->Ti*Ui)*(params->Ti*Ui))\ - /(Fe*(Ue*params->Te)*(Ue*params->Te)/(params->Te+Tm)\ - + Fi*(params->Ti*Ui)*(params->Ti*Ui)/(params->Ti+Tm)); + Tv = ( Fe*(Ue*Te)*(Ue*Te) + Fi*(Ti*Ui)*(Ti*Ui))\ + /(Fe*(Ue*Te)*(Ue*Te)/(Te+Tm) + Fi*(Ti*Ui)*(Ti*Ui)/(Ti+Tm)); if (Tv < ACS_DBL_TINY){ Tv += ACS_DBL_TINY; } - params->TvN = Tv*params->Gl/params->Cm; + TvN = Tv*Gl/Cm; } void TF(REAL Ve, REAL Vi, meanfield_t *meanfield, config_t *restrict config, - mathsbox_t *restrict mathsbox){ + Vthre_params_t *restrict Vparams, mathsbox_t *restrict mathsbox){ //PUT comments HERE!!! @@ -231,9 +250,9 @@ void TF(REAL Ve, REAL Vi, meanfield_t *meanfield, config_t *restrict config, } get_fluct_regime_varsup(Ve, Vi, config); - threshold_func(config); + threshold_func(config, Vparams); - limit = REAL_CONST(0.5)*(config->Gl/(config->TvN * config->Cm)); + limit = REAL_HALF*(config->Gl/(config->TvN * config->Cm)); /* normalement sqrt: argument = (config->Vthre - config->muV)/sqrtk(REAL_CONST(2.))/config->sV; @@ -245,10 +264,11 @@ void TF(REAL Ve, REAL Vi, meanfield_t *meanfield, config_t *restrict config, argument = (config->Vthre - config->muV)/(REAL_CONST(1.4142137))/config->sV; error_function(limit, argument, mathsbox); - + /* if (config->P0 == 0.){ - mathsbox->err_func = 1; + mathsbox->err_func = 1; a simple test } + */ config->Fout_th = (HALF*config->Gl) * mathsbox->err_func / (config->Cm*config->TvN);// REAL ONE //config->Fout_th = mathsbox->err_func ; //TEST @@ -261,16 +281,24 @@ void TF(REAL Ve, REAL Vi, meanfield_t *meanfield, config_t *restrict config, } -void RK2_midpoint_MF(REAL h, meanfield_t *meanfield, config_t *restrict config, - mathsbox_t *restrict mathsbox) { +void RK2_midpoint_MF(REAL h, meanfield_t *meanfield, + config_t *restrict config, + Vthre_params_t *restrict Vparams_Ve, + Vthre_params_t *restrict Vparams_Vi, + mathsbox_t *restrict mathsbox) { REAL lastVe = meanfield->Ve; REAL lastVi = meanfield->Vi; REAL T_inv = meanfield->Timescale_inv; - TF(lastVe, lastVi, meanfield, config, mathsbox); - REAL lastTF = config->Fout_th; + TF(lastVe, lastVi, meanfield, config, Vparams_Ve, mathsbox); + REAL lastTF_Ve = config->Fout_th; + + + TF(lastVe, lastVi, meanfield, config, Vparams_Vi, mathsbox); + REAL lastTF_Vi = config->Fout_th; + //configVe stand for TF1 i.e TF for exitatory pop. SO configVi is for TF2 //In fact no configVe and configVi just config, all in the same file. @@ -279,7 +307,7 @@ void RK2_midpoint_MF(REAL h, meanfield_t *meanfield, config_t *restrict config, meanfield->Ve = meanfield->Ve * T_inv; - meanfield->Vi += lastVi + (REAL_HALF(lastTF - lastVi) * (REAL_CONST(2.0)-h) * h); + meanfield->Vi += lastVi + (REAL_HALF(lastTF_Vi - lastVi) * (REAL_CONST(2.0)-h) * h); meanfield->Vi = meanfield->Vi * T_inv; @@ -332,7 +360,10 @@ void meanfield_model_set_global_neuron_params( and maybe is there some contamanation from the neightbourest neighbour MF! */ state_t meanfield_model_state_update( - meanfield_t *restrict meanfield, config_t *restrict config, mathsbox_t *restrict mathsbox){ + meanfield_t *restrict meanfield, config_t *restrict config, + Vthre_params_t *restrict Vparams_Ve, + Vthre_params_t *restrict Vparams_Vi, + mathsbox_t *restrict mathsbox){ /* uint16_t num_excitatory_inputs, const input_t *exc_input, uint16_t num_inhibitory_inputs, const input_t *inh_input, @@ -353,7 +384,9 @@ state_t meanfield_model_state_update( */ // the best AR update so far - RK2_midpoint_MF(meanfield->this_h, meanfield, config, mathsbox); + RK2_midpoint_MF(meanfield->this_h, meanfield, + Vparams_Ve, Vparams_Vi, + config, mathsbox); meanfield->this_h = global_params->machine_timestep_ms; return meanfield->Ve; From b21502aac509cd5475102ac717c427aa1ef8c142 Mon Sep 17 00:00:00 2001 From: Garandel Date: Tue, 26 Oct 2021 12:33:50 +0000 Subject: [PATCH 26/44] modified: ../meanfield_build.mk modified: Makefile modified: ../../../src/meanfield/implementations/meanfield_impl_standard.h renamed: ../../../src/meanfield/models/Vthre_params.h -> ../../../src/meanfield/models/P_fit_polynomial.h modified: ../../../src/meanfield/models/meanfield_model.h modified: ../../../src/meanfield/models/meanfield_model_impl.c modified: ../../../../spynnaker/pyNN/models/neuron/abstract_pynn_meanfield_model_standard.py modified: ../../../../spynnaker/pyNN/models/neuron/builds/meanfield_base.py Add the other transfert function for inhibitors in C code, -> take parameters from config.h to an other Opaque structure P_fit_polynomial.h that's compile --- .../makefiles/meanfield/meanfield_build.mk | 7 ++ .../meanfield/meanfield_model_cond/Makefile | 1 + .../implementations/meanfield_impl_standard.h | 54 +++++++++-- .../{Vthre_params.h => P_fit_polynomial.h} | 12 ++- .../src/meanfield/models/meanfield_model.h | 12 ++- .../meanfield/models/meanfield_model_impl.c | 93 ++++++++++--------- .../abstract_pynn_meanfield_model_standard.py | 7 +- .../models/neuron/builds/meanfield_base.py | 13 ++- 8 files changed, 134 insertions(+), 65 deletions(-) rename neural_modelling/src/meanfield/models/{Vthre_params.h => P_fit_polynomial.h} (52%) diff --git a/neural_modelling/makefiles/meanfield/meanfield_build.mk b/neural_modelling/makefiles/meanfield/meanfield_build.mk index 7d7ff6f8da6..b0e0f88946e 100644 --- a/neural_modelling/makefiles/meanfield/meanfield_build.mk +++ b/neural_modelling/makefiles/meanfield/meanfield_build.mk @@ -126,6 +126,12 @@ else CONFIG_H := $(call replace_source_dirs,$(CONFIG_H)) endif + ifndef P_FIT_POLYNOMIAL_H + $(error P_FIT_POLYNOMIAL_H is not set. Please select an input type header file) + else + P_FIT_POLYNOMIAL_H := $(call replace_source_dirs,$(P_FIT_POLYNOMIAL_H)) + endif + ifndef INPUT_TYPE_H $(error INPUT_TYPE_H is not set. Please select an input type header file) else @@ -154,6 +160,7 @@ else -include $(MEANFIELD_MODEL_H) \ -include $(SYNAPSE_TYPE_H) \ -include $(CONFIG_H)\ + -include $(P_FIT_POLYNOMIAL_H)\ -include $(MATHSBOX_H) \ -include $(INPUT_TYPE_H) \ -include $(THRESHOLD_TYPE_H) \ diff --git a/neural_modelling/makefiles/meanfield/meanfield_model_cond/Makefile b/neural_modelling/makefiles/meanfield/meanfield_model_cond/Makefile index d75120ae42f..fe9553b385a 100644 --- a/neural_modelling/makefiles/meanfield/meanfield_model_cond/Makefile +++ b/neural_modelling/makefiles/meanfield/meanfield_model_cond/Makefile @@ -3,6 +3,7 @@ APP = $(notdir $(CURDIR)) MEANFIELD_MODEL = $(MEANFIELD_DIR)/meanfield/models/meanfield_model_impl.c MEANFIELD_MODEL_H = $(MEANFIELD_DIR)/meanfield/models/meanfield_model_impl.h CONFIG_H = $(MEANFIELD_DIR)/meanfield/models/config.h +P_FIT_POLYNOMIAL_H = $(MEANFIELD_DIR)/meanfield/models/P_fit_polynomial.h INPUT_TYPE_H = $(MEANFIELD_DIR)/meanfield/input_types/input_type_conductance.h MATHSBOX_H = $(MEANFIELD_DIR)/meanfield/models/mathsbox.h MEANFIELD_IMPL_H = $(MEANFIELD_DIR)/meanfield/implementations/meanfield_impl_standard.h diff --git a/neural_modelling/src/meanfield/implementations/meanfield_impl_standard.h b/neural_modelling/src/meanfield/implementations/meanfield_impl_standard.h index 7336ff791b5..7e64556888f 100644 --- a/neural_modelling/src/meanfield/implementations/meanfield_impl_standard.h +++ b/neural_modelling/src/meanfield/implementations/meanfield_impl_standard.h @@ -25,6 +25,7 @@ // Includes for model parts used in this implementation #include #include +#include #include #include @@ -68,13 +69,15 @@ enum bitfield_recording_indices { };*/ -//! Array of meanfield states -> will be change in future +//! Array of meanfield states -> will be change in future , the future is now!! static meanfield_t *meanfield_array; static config_t *config_array; static mathsbox_t *mathsbox_array; +static pFitPolynomial_t *Pfit_exc_array; +static pFitPolynomial_t *Pfit_inh_array; //! Input states array static input_type_t *input_type_array; @@ -145,7 +148,25 @@ static bool meanfield_impl_initialise(uint32_t n_meanfields) { return false; } } - + + // Allocate DTCM for P fit from polyomial for exc array and copy block of data + if (sizeof(pFitPolynomial_t)) { + Pfit_exc_array = spin1_malloc(n_meanfields * sizeof(pFitPolynomial_t)); + if (Pfit_exc_array == NULL) { + log_error("Unable to allocate Pfit_exc_array - Out of DTCM"); + return false; + } + } + + // Allocate DTCM for P fit from polyomial for exc array and copy block of data + if (sizeof(pFitPolynomial_t)) { + Pfit_inh_array = spin1_malloc(n_meanfields * sizeof(pFitPolynomial_t)); + if (Pfit_inh_array == NULL) { + log_error("Unable to allocate Pfit_inh_array - Out of DTCM"); + return false; + } + } + // Allocate DTCM for mathsbox array and copy block of data if (sizeof(mathsbox_t)) { mathsbox_array = spin1_malloc(n_meanfields * sizeof(mathsbox_t)); @@ -262,7 +283,21 @@ static void neuron_impl_load_neuron_parameters( n_meanfields * sizeof(config_t)); next += n_words_needed(n_meanfields * sizeof(config_t)); } - + + if (sizeof(pFitPolynomial_t)) { + log_debug("reading pFitPolynomial exc parameters"); + spin1_memcpy(Pfit_exc_array, &address[next], + n_meanfields * sizeof(pFitPolynomial_t)); + next += n_words_needed(n_meanfields * sizeof(pFitPolynomial_t)); + } + + if (sizeof(pFitPolynomial_t)) { + log_debug("reading pFitPolynomial inh parameters"); + spin1_memcpy(Pfit_inh_array, &address[next], + n_meanfields * sizeof(pFitPolynomial_t)); + next += n_words_needed(n_meanfields * sizeof(pFitPolynomial_t)); + } + if (sizeof(mathsbox_t)) { log_debug("reading mathsbox parameters"); spin1_memcpy(mathsbox_array, &address[next], @@ -319,6 +354,9 @@ static void neuron_impl_do_timestep_update( // Get the config and mathsbox params for this neuron config_t *config_types = &config_array[meanfield_index]; + pFitPolynomial_t *Pfit_exc_types = &Pfit_exc_array[meanfield_index]; + pFitPolynomial_t *Pfit_inh_types = &Pfit_inh_array[meanfield_index]; + mathsbox_t *mathsbox_types = &mathsbox_array[meanfield_index]; // Get the input_type parameters and voltage for this neuron @@ -338,8 +376,10 @@ static void neuron_impl_do_timestep_update( // and because the index doesn't actually matter for (uint32_t i_step = n_steps_per_timestep; i_step > 0; i_step--) { // Get the voltage->firing rate - state_t firing_rate_Ve = meanfield_model_get_firing_rate_Ve(this_meanfield); - state_t firing_rate_Vi = meanfield_model_get_firing_rate_Vi(this_meanfield); + state_t firing_rate_Ve = meanfield_model_get_firing_rate_Ve( + this_meanfield); + state_t firing_rate_Vi = meanfield_model_get_firing_rate_Vi( + this_meanfield); state_t Fout_th = meanfield_model_get_Fout_th(config_types); @@ -393,7 +433,9 @@ static void neuron_impl_do_timestep_update( // update neuron parameters state_t result = meanfield_model_state_update( - this_meanfield, config_types, mathsbox_types); + this_meanfield, config_types, + Pfit_exc_types, Pfit_inh_types, + mathsbox_types); // determine if a spike should occur bool spike_now = diff --git a/neural_modelling/src/meanfield/models/Vthre_params.h b/neural_modelling/src/meanfield/models/P_fit_polynomial.h similarity index 52% rename from neural_modelling/src/meanfield/models/Vthre_params.h rename to neural_modelling/src/meanfield/models/P_fit_polynomial.h index 6e28cf6bafb..c2978f96905 100644 --- a/neural_modelling/src/meanfield/models/Vthre_params.h +++ b/neural_modelling/src/meanfield/models/P_fit_polynomial.h @@ -1,12 +1,13 @@ -#ifndef _VTHRE_PARAMS_H_ -#define _VTHRE_PARAMS_H_ +#ifndef _P_FIT_POLYNOMIAL_H_ +#define _P_FIT_POLYNOMIAL_H_ #include "../../meanfield/models/meanfield_model.h" - -typedef struct Vthre_params_t { +typedef struct pFitPolynomial_t { // nominally 'fixed' parameters - +/*! \brief a structure for the polynomial parameters coming from a single neuron fit + * MORE INFO +*/ REAL P0; REAL P1; REAL P2; @@ -18,6 +19,7 @@ typedef struct Vthre_params_t { REAL P8; REAL P9; REAL P10; +} pFitPolynomial_t; #endif \ No newline at end of file diff --git a/neural_modelling/src/meanfield/models/meanfield_model.h b/neural_modelling/src/meanfield/models/meanfield_model.h index 8a4bb14e7fb..2ef2832b8f7 100644 --- a/neural_modelling/src/meanfield/models/meanfield_model.h +++ b/neural_modelling/src/meanfield/models/meanfield_model.h @@ -37,9 +37,9 @@ struct config_t; typedef struct config_t config_t; typedef struct config_t* config_pointer_t; -struct Vthre_params_t; -typedef struct Vthre_params_t Vthre_params_t; -typedef struct Vthre_params_t* Vthre_params_pointer_t; +struct pFitPolynomial_t; +typedef struct pFitPolynomial_t pFitPolynomial_t; +typedef struct pFitPolynomial_t* pFitPolynomial_pointer_t; struct mathsbox_t; typedef struct mathsbox_t mathsbox_t; @@ -82,7 +82,11 @@ state_t meanfield_model_state_update( state_t meanfield_model_state_update( - meanfield_t *restrict meanfield, config_t *restrict config, mathsbox_t *restrict mathsbox); + meanfield_t *restrict meanfield, + config_t *restrict config, + pFitPolynomial_t *restrict Pfit_exc, + pFitPolynomial_t *restrict Pfit_inh, + mathsbox_t *restrict mathsbox); //! \brief Indicates that the neuron has spiked //! \param[in, out] neuron pointer to a neuron parameter struct which contains diff --git a/neural_modelling/src/meanfield/models/meanfield_model_impl.c b/neural_modelling/src/meanfield/models/meanfield_model_impl.c index a733248630d..0ac7d0f0327 100644 --- a/neural_modelling/src/meanfield/models/meanfield_model_impl.c +++ b/neural_modelling/src/meanfield/models/meanfield_model_impl.c @@ -22,6 +22,7 @@ #include #include "../../meanfield/models/config.h" #include "../../meanfield/models/mathsbox.h" +#include "../../meanfield/models/P_fit_polynomial.h" //#include "../../common/maths-util.h" // i.o to use SQRT(x) and SQR(a) //! The global parameters of the Izhekevich neuron model @@ -86,8 +87,14 @@ void error_function( REAL x, REAL factor, mathsbox_t *restrict mathsbox){ } -void threshold_func(config_t *restrict config, Vthre_params_t *restrict Vparams) +void threshold_func(config_t *restrict config, pFitPolynomial_t *restrict pfit) { + /* + threshold function coming from : + Neural Computation 31, 653–680 (2019) doi:10.1162/neco_a_01173 + where P's are polynomials parameters involve in a + voltage-effective threshold. + */ /* setting by default to True the square because when use by external modules, coeff[5:]=np.zeros(3) @@ -97,36 +104,33 @@ void threshold_func(config_t *restrict config, Vthre_params_t *restrict Vparams) but not for now */ - REAL muV0 = config->muV0;//=-0.06; - REAL DmuV0 = config->DmuV0;//=0.01; + REAL muV0 = config->muV0; + REAL DmuV0 = config->DmuV0; - REAL sV0 = config->sV0;//=0.004; - REAL DsV0 = config->DsV0;//=0.006; + REAL sV0 = config->sV0; + REAL DsV0 = config->DsV0; - REAL TvN0 = config->TvN0;//=0.5; - REAL DTvN0 = config->DTvN0;//=1.; + REAL TvN0 = config->TvN0; + REAL DTvN0 = config->DTvN0; - REAL muV = config->muV;//=0.; - REAL sV = config->sV;//=0.; - //REAL muGn = config->muGn;//=0.; - REAL TvN = config->TvN;//=0.; - REAL Vthre = config->Vthre;//=0.; - //REAL Fout_th = config->Fout_th;//=0.; - - REAL P0 = Vparams->P0; - REAL P1 = Vparams->P1; - REAL P2 = Vparams->P2; - REAL P3 = Vparams->P3; - REAL P4 = Vparams->P4; - REAL P5 = Vparams->P5; - REAL P6 = Vparams->P6; - REAL P7 = Vparams->P7; - REAL P8 = Vparams->P8; - REAL P9 = Vparams->P9; - REAL P10 = Vparams->P10; - - + REAL muV = config->muV; + REAL sV = config->sV; + //REAL muGn = config->muGn; + REAL TvN = config->TvN; + REAL Vthre = config->Vthre; + //REAL Fout_th = config->Fout_th; + REAL P0 = pfit->P0; + REAL P1 = pfit->P1; + REAL P2 = pfit->P2; + REAL P3 = pfit->P3; + REAL P4 = pfit->P4; + REAL P5 = pfit->P5; + REAL P6 = pfit->P6; + REAL P7 = pfit->P7; + REAL P8 = pfit->P8; + REAL P9 = pfit->P9; + REAL P10 = pfit->P10; // + 0.\ //P4*np.log(muGn) @@ -172,9 +176,6 @@ void get_fluct_regime_varsup(REAL Ve, REAL Vi, config_t *restrict config) REAL sV = config->sV; REAL TvN = config->TvN; - - - // here TOTAL (sum over synapses) excitatory and inhibitory input Fe = Ve * (REAL_CONST(1.)-gei)*pconnec*Ntot; // default is 1 !! @@ -234,7 +235,7 @@ void get_fluct_regime_varsup(REAL Ve, REAL Vi, config_t *restrict config) void TF(REAL Ve, REAL Vi, meanfield_t *meanfield, config_t *restrict config, - Vthre_params_t *restrict Vparams, mathsbox_t *restrict mathsbox){ + pFitPolynomial_t *restrict Pfit, mathsbox_t *restrict mathsbox){ //PUT comments HERE!!! @@ -250,9 +251,9 @@ void TF(REAL Ve, REAL Vi, meanfield_t *meanfield, config_t *restrict config, } get_fluct_regime_varsup(Ve, Vi, config); - threshold_func(config, Vparams); + threshold_func(config, Pfit); - limit = REAL_HALF*(config->Gl/(config->TvN * config->Cm)); + limit = REAL_HALF(config->Gl/(config->TvN * config->Cm)); /* normalement sqrt: argument = (config->Vthre - config->muV)/sqrtk(REAL_CONST(2.))/config->sV; @@ -283,8 +284,8 @@ void TF(REAL Ve, REAL Vi, meanfield_t *meanfield, config_t *restrict config, void RK2_midpoint_MF(REAL h, meanfield_t *meanfield, config_t *restrict config, - Vthre_params_t *restrict Vparams_Ve, - Vthre_params_t *restrict Vparams_Vi, + pFitPolynomial_t *restrict Pfit_exc, + pFitPolynomial_t *restrict Pfit_inh, mathsbox_t *restrict mathsbox) { REAL lastVe = meanfield->Ve; @@ -292,18 +293,18 @@ void RK2_midpoint_MF(REAL h, meanfield_t *meanfield, REAL T_inv = meanfield->Timescale_inv; - TF(lastVe, lastVi, meanfield, config, Vparams_Ve, mathsbox); + TF(lastVe, lastVi, meanfield, config, Pfit_exc, mathsbox); REAL lastTF_Ve = config->Fout_th; - TF(lastVe, lastVi, meanfield, config, Vparams_Vi, mathsbox); + TF(lastVe, lastVi, meanfield, config, Pfit_inh, mathsbox); REAL lastTF_Vi = config->Fout_th; //configVe stand for TF1 i.e TF for exitatory pop. SO configVi is for TF2 //In fact no configVe and configVi just config, all in the same file. - meanfield->Ve += lastVe + (REAL_HALF(lastTF - lastVe) * (REAL_CONST(2.0)-h) * h); + meanfield->Ve += lastVe + (REAL_HALF(lastTF_Ve - lastVe) * (REAL_CONST(2.0)-h) * h); meanfield->Ve = meanfield->Ve * T_inv; @@ -360,9 +361,10 @@ void meanfield_model_set_global_neuron_params( and maybe is there some contamanation from the neightbourest neighbour MF! */ state_t meanfield_model_state_update( - meanfield_t *restrict meanfield, config_t *restrict config, - Vthre_params_t *restrict Vparams_Ve, - Vthre_params_t *restrict Vparams_Vi, + meanfield_t *restrict meanfield, + config_t *restrict config, + pFitPolynomial_t *restrict Pfit_exc, + pFitPolynomial_t *restrict Pfit_inh, mathsbox_t *restrict mathsbox){ /* uint16_t num_excitatory_inputs, const input_t *exc_input, @@ -384,9 +386,12 @@ state_t meanfield_model_state_update( */ // the best AR update so far - RK2_midpoint_MF(meanfield->this_h, meanfield, - Vparams_Ve, Vparams_Vi, - config, mathsbox); + RK2_midpoint_MF(meanfield->this_h, + meanfield, + config, + Pfit_exc, + Pfit_inh, + mathsbox); meanfield->this_h = global_params->machine_timestep_ms; return meanfield->Ve; diff --git a/spynnaker/pyNN/models/neuron/abstract_pynn_meanfield_model_standard.py b/spynnaker/pyNN/models/neuron/abstract_pynn_meanfield_model_standard.py index 9790ab5e479..4d21723a697 100644 --- a/spynnaker/pyNN/models/neuron/abstract_pynn_meanfield_model_standard.py +++ b/spynnaker/pyNN/models/neuron/abstract_pynn_meanfield_model_standard.py @@ -32,7 +32,8 @@ class AbstractPyNNMeanfieldModelStandard(AbstractPyNNNeuronModel): default_population_parameters = _population_parameters def __init__( - self, model_name, binary, neuron_model, config, + self, model_name, binary, neuron_model, + config, Vthre_params_Ve, Vthre_params_Vi, mathsbox, input_type, synapse_type, threshold_type, additional_input_type=None): """ @@ -49,7 +50,9 @@ def __init__( :type additional_input_type: AbstractAdditionalInput or None """ super().__init__(MeanfieldImplStandard( - model_name, binary, neuron_model, config, mathsbox, input_type, + model_name, binary, neuron_model, + config, #PUT HERE + mathsbox, input_type, synapse_type, threshold_type, additional_input_type)) @overrides(AbstractPyNNNeuronModel.create_vertex, diff --git a/spynnaker/pyNN/models/neuron/builds/meanfield_base.py b/spynnaker/pyNN/models/neuron/builds/meanfield_base.py index 959f69a639e..0986d49888c 100644 --- a/spynnaker/pyNN/models/neuron/builds/meanfield_base.py +++ b/spynnaker/pyNN/models/neuron/builds/meanfield_base.py @@ -150,13 +150,13 @@ def __init__(self, Ntot, gei, ext_drive, afferent_exc_fraction, Gl, Cm, El, - p0, p1, p2, p3, p4, p5, - p6, p7, p8, p9, p10, muV, muV0,DmuV0, sV, sV0, DsV0, muGn, TvN, TvN0, DTvN0, Vthre, Fout_th) + Vthre_params_Ve = + Vthre_params_vi = mathsbox = Mathsbox(sample, err_func) synapse_type = SynapseTypeExponential( tau_syn_E, tau_syn_I, isyn_exc, isyn_inh) @@ -166,6 +166,11 @@ def __init__(self, super().__init__( model_name="meanfield_model_cond", binary="meanfield_model_cond.aplx", - neuron_model=neuron_model, config=config, mathsbox=mathsbox, - input_type=input_type, synapse_type=synapse_type, + neuron_model=neuron_model, + config=config, + Vthre_params_Ve = , #PUT HERE + Vthre_params_vi = , #PUT HERE + mathsbox=mathsbox, + input_type=input_type, + synapse_type=synapse_type, threshold_type=threshold_type) From e7ab542f747c59b1379368082084916f15480bea Mon Sep 17 00:00:00 2001 From: Garandel Date: Tue, 26 Oct 2021 13:10:58 +0000 Subject: [PATCH 27/44] modified: ../meanfield_build.mk modified: Makefile modified: ../../../src/meanfield/implementations/meanfield_impl_standard.h modified: ../../../src/meanfield/models/meanfield_model.h modified: ../../../src/meanfield/models/meanfield_model_impl.c renamed: ../../../src/meanfield/models/config.h -> ../../../src/meanfield/models/params_from_network.h renames config.h to params_from_network.h in order to be more precise in the correspondance btw code and litterature. change names of types, arrays and structure. compilation is ok --- .../makefiles/meanfield/meanfield_build.mk | 8 +- .../meanfield/meanfield_model_cond/Makefile | 2 +- .../implementations/meanfield_impl_standard.h | 36 +++--- .../src/meanfield/models/meanfield_model.h | 10 +- .../meanfield/models/meanfield_model_impl.c | 115 +++++++++--------- .../{config.h => params_from_network.h} | 4 +- 6 files changed, 89 insertions(+), 86 deletions(-) rename neural_modelling/src/meanfield/models/{config.h => params_from_network.h} (93%) diff --git a/neural_modelling/makefiles/meanfield/meanfield_build.mk b/neural_modelling/makefiles/meanfield/meanfield_build.mk index b0e0f88946e..b698a223029 100644 --- a/neural_modelling/makefiles/meanfield/meanfield_build.mk +++ b/neural_modelling/makefiles/meanfield/meanfield_build.mk @@ -120,10 +120,10 @@ else endif - ifndef CONFIG_H - $(error CONFIG_H is not set. Please select an input type header file) + ifndef PARAMS_FROM_NETWORK_H + $(error PARAMS_FROM_NETWORK_H is not set. Please select an input type header file) else - CONFIG_H := $(call replace_source_dirs,$(CONFIG_H)) + PARAMS_FROM_NETWORK_H := $(call replace_source_dirs,$(PARAMS_FROM_NETWORK_H)) endif ifndef P_FIT_POLYNOMIAL_H @@ -159,7 +159,7 @@ else MEANFIELD_INCLUDES := \ -include $(MEANFIELD_MODEL_H) \ -include $(SYNAPSE_TYPE_H) \ - -include $(CONFIG_H)\ + -include $(PARAMS_FROM_NETWORK_H)\ -include $(P_FIT_POLYNOMIAL_H)\ -include $(MATHSBOX_H) \ -include $(INPUT_TYPE_H) \ diff --git a/neural_modelling/makefiles/meanfield/meanfield_model_cond/Makefile b/neural_modelling/makefiles/meanfield/meanfield_model_cond/Makefile index fe9553b385a..8dc3058b4be 100644 --- a/neural_modelling/makefiles/meanfield/meanfield_model_cond/Makefile +++ b/neural_modelling/makefiles/meanfield/meanfield_model_cond/Makefile @@ -2,7 +2,7 @@ APP = $(notdir $(CURDIR)) MEANFIELD_MODEL = $(MEANFIELD_DIR)/meanfield/models/meanfield_model_impl.c MEANFIELD_MODEL_H = $(MEANFIELD_DIR)/meanfield/models/meanfield_model_impl.h -CONFIG_H = $(MEANFIELD_DIR)/meanfield/models/config.h +PARAMS_FROM_NETWORK_H = $(MEANFIELD_DIR)/meanfield/models/params_from_network.h P_FIT_POLYNOMIAL_H = $(MEANFIELD_DIR)/meanfield/models/P_fit_polynomial.h INPUT_TYPE_H = $(MEANFIELD_DIR)/meanfield/input_types/input_type_conductance.h MATHSBOX_H = $(MEANFIELD_DIR)/meanfield/models/mathsbox.h diff --git a/neural_modelling/src/meanfield/implementations/meanfield_impl_standard.h b/neural_modelling/src/meanfield/implementations/meanfield_impl_standard.h index 7e64556888f..c68bd5d7b15 100644 --- a/neural_modelling/src/meanfield/implementations/meanfield_impl_standard.h +++ b/neural_modelling/src/meanfield/implementations/meanfield_impl_standard.h @@ -24,7 +24,7 @@ // Includes for model parts used in this implementation #include -#include +#include #include #include @@ -72,7 +72,7 @@ enum bitfield_recording_indices { //! Array of meanfield states -> will be change in future , the future is now!! static meanfield_t *meanfield_array; -static config_t *config_array; +static ParamsFromNetwork_t *pNetwork_array; static mathsbox_t *mathsbox_array; @@ -141,9 +141,9 @@ static bool meanfield_impl_initialise(uint32_t n_meanfields) { } // Allocate DTCM for config array and copy block of data - if (sizeof(config_t)) { - config_array = spin1_malloc(n_meanfields * sizeof(config_t)); - if (config_array == NULL) { + if (sizeof(ParamsFromNetwork_t)) { + pNetwork_array = spin1_malloc(n_meanfields * sizeof(ParamsFromNetwork_t)); + if (pNetwork_array == NULL) { log_error("Unable to allocate config array - Out of DTCM"); return false; } @@ -277,11 +277,11 @@ static void neuron_impl_load_neuron_parameters( next += n_words_needed(n_meanfields * sizeof(meanfield_t)); } - if (sizeof(config_t)) { + if (sizeof(ParamsFromNetwork_t)) { log_debug("reading config parameters"); - spin1_memcpy(config_array, &address[next], - n_meanfields * sizeof(config_t)); - next += n_words_needed(n_meanfields * sizeof(config_t)); + spin1_memcpy(pNetwork_array, &address[next], + n_meanfields * sizeof(ParamsFromNetwork_t)); + next += n_words_needed(n_meanfields * sizeof(ParamsFromNetwork_t)); } if (sizeof(pFitPolynomial_t)) { @@ -352,8 +352,8 @@ static void neuron_impl_do_timestep_update( // Get the neuron itself meanfield_t *this_meanfield = &meanfield_array[meanfield_index]; - // Get the config and mathsbox params for this neuron - config_t *config_types = &config_array[meanfield_index]; + // Get the Params from network and mathsbox params for this neuron + ParamsFromNetwork_t *pNetwork_types = &pNetwork_array[meanfield_index]; pFitPolynomial_t *Pfit_exc_types = &Pfit_exc_array[meanfield_index]; pFitPolynomial_t *Pfit_inh_types = &Pfit_inh_array[meanfield_index]; @@ -381,7 +381,7 @@ static void neuron_impl_do_timestep_update( state_t firing_rate_Vi = meanfield_model_get_firing_rate_Vi( this_meanfield); - state_t Fout_th = meanfield_model_get_Fout_th(config_types); + state_t Fout_th = meanfield_model_get_Fout_th(pNetwork_types); // Get the exc and inh values from the synapses input_t exc_values[NUM_EXCITATORY_RECEPTORS]; @@ -433,7 +433,7 @@ static void neuron_impl_do_timestep_update( // update neuron parameters state_t result = meanfield_model_state_update( - this_meanfield, config_types, + this_meanfield, pNetwork_types, Pfit_exc_types, Pfit_inh_types, mathsbox_types); @@ -459,7 +459,7 @@ static void neuron_impl_do_timestep_update( // Shape the existing input according to the included rule synapse_types_shape_input(the_synapse_type); - if (config_types->Fout_th==0.0) { + if (pNetwork_types->Fout_th==0.0) { has_spiked = true; } } @@ -500,11 +500,11 @@ static void neuron_impl_store_neuron_parameters( next += n_words_needed(n_meanfields * sizeof(meanfield_t)); } - if (sizeof(config_t)) { + if (sizeof(ParamsFromNetwork_t)) { log_debug("writing input type parameters"); - spin1_memcpy(&address[next], config_array, - n_meanfields * sizeof(config_t)); - next += n_words_needed(n_meanfields * sizeof(config_t)); + spin1_memcpy(&address[next], pNetwork_array, + n_meanfields * sizeof(ParamsFromNetwork_t)); + next += n_words_needed(n_meanfields * sizeof(ParamsFromNetwork_t)); } } diff --git a/neural_modelling/src/meanfield/models/meanfield_model.h b/neural_modelling/src/meanfield/models/meanfield_model.h index 2ef2832b8f7..8669138e3a2 100644 --- a/neural_modelling/src/meanfield/models/meanfield_model.h +++ b/neural_modelling/src/meanfield/models/meanfield_model.h @@ -33,9 +33,9 @@ struct meanfield_t; typedef struct meanfield_t meanfield_t; typedef struct meanfield_t* meanfield_pointer_t; -struct config_t; -typedef struct config_t config_t; -typedef struct config_t* config_pointer_t; +struct ParamsFromNetwork_t; +typedef struct ParamsFromNetwork_t ParamsFromNetwork_t; +typedef struct ParamsFromNetwork_t* ParamsFromNetwork_pointer_t; struct pFitPolynomial_t; typedef struct pFitPolynomial_t pFitPolynomial_t; @@ -83,7 +83,7 @@ state_t meanfield_model_state_update( state_t meanfield_model_state_update( meanfield_t *restrict meanfield, - config_t *restrict config, + ParamsFromNetwork_t *restrict params_from_network, pFitPolynomial_t *restrict Pfit_exc, pFitPolynomial_t *restrict Pfit_inh, mathsbox_t *restrict mathsbox); @@ -100,7 +100,7 @@ void neuron_model_has_spiked(meanfield_t *restrict meanfield); //! parameters specified in neuron state_t meanfield_model_get_firing_rate_Ve(const meanfield_t *meanfield); state_t meanfield_model_get_firing_rate_Vi(const meanfield_t *meanfield); -state_t meanfield_model_get_Fout_th(const config_t *config); +state_t meanfield_model_get_Fout_th(const ParamsFromNetwork_t *params_from_network); //! \brief printout of state variables i.e. those values that might change //! \param[in] neuron: a pointer to a neuron parameter struct which contains all diff --git a/neural_modelling/src/meanfield/models/meanfield_model_impl.c b/neural_modelling/src/meanfield/models/meanfield_model_impl.c index 0ac7d0f0327..aabf6a4e54f 100644 --- a/neural_modelling/src/meanfield/models/meanfield_model_impl.c +++ b/neural_modelling/src/meanfield/models/meanfield_model_impl.c @@ -20,7 +20,7 @@ #include "../../meanfield/models/meanfield_model_impl.h" #include -#include "../../meanfield/models/config.h" +#include "../../meanfield/models/params_from_network.h" #include "../../meanfield/models/mathsbox.h" #include "../../meanfield/models/P_fit_polynomial.h" //#include "../../common/maths-util.h" // i.o to use SQRT(x) and SQR(a) @@ -87,7 +87,7 @@ void error_function( REAL x, REAL factor, mathsbox_t *restrict mathsbox){ } -void threshold_func(config_t *restrict config, pFitPolynomial_t *restrict pfit) +void threshold_func(ParamsFromNetwork_t *restrict pNetwork, pFitPolynomial_t *restrict pfit) { /* threshold function coming from : @@ -104,21 +104,21 @@ void threshold_func(config_t *restrict config, pFitPolynomial_t *restrict pfit) but not for now */ - REAL muV0 = config->muV0; - REAL DmuV0 = config->DmuV0; + REAL muV0 = pNetwork->muV0; + REAL DmuV0 = pNetwork->DmuV0; - REAL sV0 = config->sV0; - REAL DsV0 = config->DsV0; + REAL sV0 = pNetwork->sV0; + REAL DsV0 = pNetwork->DsV0; - REAL TvN0 = config->TvN0; - REAL DTvN0 = config->DTvN0; + REAL TvN0 = pNetwork->TvN0; + REAL DTvN0 = pNetwork->DTvN0; - REAL muV = config->muV; - REAL sV = config->sV; - //REAL muGn = config->muGn; - REAL TvN = config->TvN; - REAL Vthre = config->Vthre; - //REAL Fout_th = config->Fout_th; + REAL muV = pNetwork->muV; + REAL sV = pNetwork->sV; + //REAL muGn = pNetwork->muGn; + REAL TvN = pNetwork->TvN; + REAL Vthre = pNetwork->Vthre; + //REAL Fout_th = pNetwork->Fout_th; REAL P0 = pfit->P0; REAL P1 = pfit->P1; @@ -145,11 +145,11 @@ void threshold_func(config_t *restrict config, pFitPolynomial_t *restrict pfit) + P9*((muV-muV0)/DmuV0)*((TvN-TvN0)/DTvN0)\ + P10*((sV-sV0)/DsV0)*((TvN-TvN0)/DTvN0); - config->Vthre = Vthre; + pNetwork->Vthre = Vthre; } -void get_fluct_regime_varsup(REAL Ve, REAL Vi, config_t *restrict config) +void get_fluct_regime_varsup(REAL Ve, REAL Vi, ParamsFromNetwork_t *restrict pNetwork) { REAL Fe; @@ -158,23 +158,23 @@ void get_fluct_regime_varsup(REAL Ve, REAL Vi, config_t *restrict config) REAL Ue, Ui; REAL Tm, Tv; - REAL gei = config->gei; - REAL pconnec = config->pconnec; - REAL Ntot = config->Ntot; - REAL Qe = config->Qe; - REAL Qi = config->Qi; - REAL Te = config->Te; - REAL Ti = config->Ti; - REAL Gl = config->Gl; - REAL El = config->El; - REAL Ei = config->Ei; - REAL Ee = config->Ee; - REAL Cm = config->Cm; + REAL gei = pNetwork->gei; + REAL pconnec = pNetwork->pconnec; + REAL Ntot = pNetwork->Ntot; + REAL Qe = pNetwork->Qe; + REAL Qi = pNetwork->Qi; + REAL Te = pNetwork->Te; + REAL Ti = pNetwork->Ti; + REAL Gl = pNetwork->Gl; + REAL El = pNetwork->El; + REAL Ei = pNetwork->Ei; + REAL Ee = pNetwork->Ee; + REAL Cm = pNetwork->Cm; - REAL muV = config->muV; - REAL muGn = config->muGn; - REAL sV = config->sV; - REAL TvN = config->TvN; + REAL muV = pNetwork->muV; + REAL muGn = pNetwork->muGn; + REAL sV = pNetwork->sV; + REAL TvN = pNetwork->TvN; // here TOTAL (sum over synapses) excitatory and inhibitory input @@ -234,8 +234,11 @@ void get_fluct_regime_varsup(REAL Ve, REAL Vi, config_t *restrict config) } -void TF(REAL Ve, REAL Vi, meanfield_t *meanfield, config_t *restrict config, - pFitPolynomial_t *restrict Pfit, mathsbox_t *restrict mathsbox){ +void TF(REAL Ve, REAL Vi, + meanfield_t *meanfield, + ParamsFromNetwork_t *restrict pNetwork, + pFitPolynomial_t *restrict Pfit, + mathsbox_t *restrict mathsbox){ //PUT comments HERE!!! @@ -250,40 +253,40 @@ void TF(REAL Ve, REAL Vi, meanfield_t *meanfield, config_t *restrict config, Vi += ACS_DBL_TINY; } - get_fluct_regime_varsup(Ve, Vi, config); - threshold_func(config, Pfit); + get_fluct_regime_varsup(Ve, Vi, pNetwork); + threshold_func(pNetwork, Pfit); - limit = REAL_HALF(config->Gl/(config->TvN * config->Cm)); + limit = REAL_HALF(pNetwork->Gl/(pNetwork->TvN * pNetwork->Cm)); /* normalement sqrt: - argument = (config->Vthre - config->muV)/sqrtk(REAL_CONST(2.))/config->sV; + argument = (pNetwork->Vthre - pNetwork->muV)/sqrtk(REAL_CONST(2.))/pNetwork->sV; */ - if (config->sVsV += ACS_DBL_TINY; + if (pNetwork->sVsV += ACS_DBL_TINY; } - argument = (config->Vthre - config->muV)/(REAL_CONST(1.4142137))/config->sV; + argument = (pNetwork->Vthre - pNetwork->muV)/(REAL_CONST(1.4142137))/pNetwork->sV; error_function(limit, argument, mathsbox); /* - if (config->P0 == 0.){ + if (pNetwork->P0 == 0.){ mathsbox->err_func = 1; a simple test } */ - config->Fout_th = (HALF*config->Gl) * mathsbox->err_func / (config->Cm*config->TvN);// REAL ONE - //config->Fout_th = mathsbox->err_func ; //TEST + pNetwork->Fout_th = (HALF*pNetwork->Gl) * mathsbox->err_func / (pNetwork->Cm*pNetwork->TvN);// REAL ONE + //pNetwork->Fout_th = mathsbox->err_func ; //TEST - if (config->Fout_th < ACS_DBL_TINY){ - config->Fout_th += ACS_DBL_TINY; + if (pNetwork->Fout_th < ACS_DBL_TINY){ + pNetwork->Fout_th += ACS_DBL_TINY; } } void RK2_midpoint_MF(REAL h, meanfield_t *meanfield, - config_t *restrict config, + ParamsFromNetwork_t *restrict pNetwork, pFitPolynomial_t *restrict Pfit_exc, pFitPolynomial_t *restrict Pfit_inh, mathsbox_t *restrict mathsbox) { @@ -293,12 +296,12 @@ void RK2_midpoint_MF(REAL h, meanfield_t *meanfield, REAL T_inv = meanfield->Timescale_inv; - TF(lastVe, lastVi, meanfield, config, Pfit_exc, mathsbox); - REAL lastTF_Ve = config->Fout_th; + TF(lastVe, lastVi, meanfield, pNetwork, Pfit_exc, mathsbox); + REAL lastTF_Ve = pNetwork->Fout_th; - TF(lastVe, lastVi, meanfield, config, Pfit_inh, mathsbox); - REAL lastTF_Vi = config->Fout_th; + TF(lastVe, lastVi, meanfield, pNetwork, Pfit_inh, mathsbox); + REAL lastTF_Vi = pNetwork->Fout_th; //configVe stand for TF1 i.e TF for exitatory pop. SO configVi is for TF2 //In fact no configVe and configVi just config, all in the same file. @@ -362,7 +365,7 @@ void meanfield_model_set_global_neuron_params( */ state_t meanfield_model_state_update( meanfield_t *restrict meanfield, - config_t *restrict config, + ParamsFromNetwork_t *restrict pNetwork, pFitPolynomial_t *restrict Pfit_exc, pFitPolynomial_t *restrict Pfit_inh, mathsbox_t *restrict mathsbox){ @@ -370,7 +373,7 @@ state_t meanfield_model_state_update( uint16_t num_excitatory_inputs, const input_t *exc_input, uint16_t num_inhibitory_inputs, const input_t *inh_input, input_t external_bias, meanfield_t *restrict meanfield, - config_t *restrict config) { + ParamsFromNetwork_t *restrict pNetwork) { REAL total_exc = 0; REAL total_inh = 0; @@ -388,7 +391,7 @@ state_t meanfield_model_state_update( // the best AR update so far RK2_midpoint_MF(meanfield->this_h, meanfield, - config, + pNetwork, Pfit_exc, Pfit_inh, mathsbox); @@ -421,8 +424,8 @@ state_t meanfield_model_get_firing_rate_Vi(const meanfield_t *meanfield) { return meanfield->Vi; } -state_t meanfield_model_get_Fout_th(const config_t *config){ - return config->Fout_th; +state_t meanfield_model_get_Fout_th(const ParamsFromNetwork_t *pNetwork){ + return pNetwork->Fout_th; } diff --git a/neural_modelling/src/meanfield/models/config.h b/neural_modelling/src/meanfield/models/params_from_network.h similarity index 93% rename from neural_modelling/src/meanfield/models/config.h rename to neural_modelling/src/meanfield/models/params_from_network.h index f3fa1807386..85bc46dfe8e 100644 --- a/neural_modelling/src/meanfield/models/config.h +++ b/neural_modelling/src/meanfield/models/params_from_network.h @@ -8,7 +8,7 @@ typedef struct config_t config_t; typedef struct config_t* config_t;*/ -typedef struct config_t { +typedef struct ParamsFromNetwork_t { // nominally 'fixed' parameters REAL pconnec; REAL Qe; @@ -48,7 +48,7 @@ typedef struct config_t { REAL Vthre; REAL Fout_th; -} config_t; +} ParamsFromNetwork_t; /* typedef struct global_toolbox_params_t { From 886ead1acd60d9fd14906a4e57845af17c23542d Mon Sep 17 00:00:00 2001 From: Garandel Date: Tue, 26 Oct 2021 13:29:58 +0000 Subject: [PATCH 28/44] modified: ../../../src/meanfield/models/meanfield_model.h modified: ../../../src/meanfield/models/params_from_network.h was changeing mathsbox.h for estimate_err_func.h but go back bcs I don't know if I will implement other function inside mathsbox and not just error function --- neural_modelling/src/meanfield/models/meanfield_model.h | 8 ++++---- .../src/meanfield/models/params_from_network.h | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/neural_modelling/src/meanfield/models/meanfield_model.h b/neural_modelling/src/meanfield/models/meanfield_model.h index 8669138e3a2..e8cf94f830f 100644 --- a/neural_modelling/src/meanfield/models/meanfield_model.h +++ b/neural_modelling/src/meanfield/models/meanfield_model.h @@ -41,9 +41,9 @@ struct pFitPolynomial_t; typedef struct pFitPolynomial_t pFitPolynomial_t; typedef struct pFitPolynomial_t* pFitPolynomial_pointer_t; -struct mathsbox_t; -typedef struct mathsbox_t mathsbox_t; -typedef struct mathsbox_t* mathsbox_pointer_t; +struct EstimateErrFunc_t; +typedef struct EstimateErrFunc_t EstimateErrFunc_t; +typedef struct EstimateErrFunc_t* EstimateErrFunc_pointer_t; //! Forward declaration of global neuron parameters struct global_neuron_params_t; @@ -86,7 +86,7 @@ state_t meanfield_model_state_update( ParamsFromNetwork_t *restrict params_from_network, pFitPolynomial_t *restrict Pfit_exc, pFitPolynomial_t *restrict Pfit_inh, - mathsbox_t *restrict mathsbox); + EstimateErrFunc_t *restrict err_func); //! \brief Indicates that the neuron has spiked //! \param[in, out] neuron pointer to a neuron parameter struct which contains diff --git a/neural_modelling/src/meanfield/models/params_from_network.h b/neural_modelling/src/meanfield/models/params_from_network.h index 85bc46dfe8e..a70b8f29bbd 100644 --- a/neural_modelling/src/meanfield/models/params_from_network.h +++ b/neural_modelling/src/meanfield/models/params_from_network.h @@ -1,5 +1,5 @@ -#ifndef _CONFIG_H_ -#define _CONFIG_H_ +#ifndef _PARAMS_FROM_NETWORK_H_ +#define _PARAMS_FROM_NETWORK_H_ #include "../../meanfield/models/meanfield_model.h" From fd2931844c2b10c5f332a00ea2a052689e52068a Mon Sep 17 00:00:00 2001 From: Garandel Date: Tue, 26 Oct 2021 13:32:42 +0000 Subject: [PATCH 29/44] modified: ../../../src/meanfield/models/meanfield_model.h wasn't go back totaly --- neural_modelling/src/meanfield/models/meanfield_model.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/neural_modelling/src/meanfield/models/meanfield_model.h b/neural_modelling/src/meanfield/models/meanfield_model.h index e8cf94f830f..8669138e3a2 100644 --- a/neural_modelling/src/meanfield/models/meanfield_model.h +++ b/neural_modelling/src/meanfield/models/meanfield_model.h @@ -41,9 +41,9 @@ struct pFitPolynomial_t; typedef struct pFitPolynomial_t pFitPolynomial_t; typedef struct pFitPolynomial_t* pFitPolynomial_pointer_t; -struct EstimateErrFunc_t; -typedef struct EstimateErrFunc_t EstimateErrFunc_t; -typedef struct EstimateErrFunc_t* EstimateErrFunc_pointer_t; +struct mathsbox_t; +typedef struct mathsbox_t mathsbox_t; +typedef struct mathsbox_t* mathsbox_pointer_t; //! Forward declaration of global neuron parameters struct global_neuron_params_t; @@ -86,7 +86,7 @@ state_t meanfield_model_state_update( ParamsFromNetwork_t *restrict params_from_network, pFitPolynomial_t *restrict Pfit_exc, pFitPolynomial_t *restrict Pfit_inh, - EstimateErrFunc_t *restrict err_func); + mathsbox_t *restrict mathsbox); //! \brief Indicates that the neuron has spiked //! \param[in, out] neuron pointer to a neuron parameter struct which contains From f2dd0c1495e16f999738081a5ffd4035ae7cca6b Mon Sep 17 00:00:00 2001 From: Garandel Date: Tue, 26 Oct 2021 13:46:03 +0000 Subject: [PATCH 30/44] modified: abstract_pynn_meanfield_model_standard.py modified: builds/meanfield_base.py modified: implementations/meanfield_impl_standard.py renamed: neuron_models/config.py -> neuron_models/params_from_network.py change name config.py for params_from_network.py and so in files --- .../abstract_pynn_meanfield_model_standard.py | 4 +-- .../models/neuron/builds/meanfield_base.py | 26 +++++++++---------- .../meanfield_impl_standard.py | 15 ++++++----- .../{config.py => params_from_network.py} | 2 +- 4 files changed, 24 insertions(+), 23 deletions(-) rename spynnaker/pyNN/models/neuron/neuron_models/{config.py => params_from_network.py} (99%) diff --git a/spynnaker/pyNN/models/neuron/abstract_pynn_meanfield_model_standard.py b/spynnaker/pyNN/models/neuron/abstract_pynn_meanfield_model_standard.py index 4d21723a697..1d608fff2d8 100644 --- a/spynnaker/pyNN/models/neuron/abstract_pynn_meanfield_model_standard.py +++ b/spynnaker/pyNN/models/neuron/abstract_pynn_meanfield_model_standard.py @@ -33,7 +33,7 @@ class AbstractPyNNMeanfieldModelStandard(AbstractPyNNNeuronModel): def __init__( self, model_name, binary, neuron_model, - config, Vthre_params_Ve, Vthre_params_Vi, + params_from_network, Vthre_params_Ve, Vthre_params_Vi, mathsbox, input_type, synapse_type, threshold_type, additional_input_type=None): """ @@ -51,7 +51,7 @@ def __init__( """ super().__init__(MeanfieldImplStandard( model_name, binary, neuron_model, - config, #PUT HERE + params_from_network, #PUT HERE mathsbox, input_type, synapse_type, threshold_type, additional_input_type)) diff --git a/spynnaker/pyNN/models/neuron/builds/meanfield_base.py b/spynnaker/pyNN/models/neuron/builds/meanfield_base.py index 0986d49888c..85760110706 100644 --- a/spynnaker/pyNN/models/neuron/builds/meanfield_base.py +++ b/spynnaker/pyNN/models/neuron/builds/meanfield_base.py @@ -15,7 +15,7 @@ from spynnaker.pyNN.models.neuron.input_types import InputTypeConductance from spynnaker.pyNN.models.neuron.neuron_models import MeanfieldModelEitn -from spynnaker.pyNN.models.neuron.neuron_models import Config +from spynnaker.pyNN.models.neuron.neuron_models import ParamsFromNetwork from spynnaker.pyNN.models.neuron.neuron_models import Mathsbox from spynnaker.pyNN.models.neuron.synapse_types import SynapseTypeExponential from spynnaker.pyNN.models.neuron.threshold_types import ThresholdTypeStatic @@ -144,17 +144,17 @@ def __init__(self, neuron_model = MeanfieldModelEitn(nbr, a, b, tauw, Trefrac, Vreset, delta_v, ampnoise, Timescale_inv, Ve, Vi) - config = Config(pconnec, q_exc, q_inh, - Tsyn_exc, Tsyn_inh, - Erev_exc, Erev_inh, - Ntot, gei, ext_drive, - afferent_exc_fraction, - Gl, Cm, El, - muV, muV0,DmuV0, - sV, sV0, DsV0, - muGn, - TvN, TvN0, DTvN0, - Vthre, Fout_th) + params_from_network = ParamsFromNetwork(pconnec, q_exc, q_inh, + Tsyn_exc, Tsyn_inh, + Erev_exc, Erev_inh, + Ntot, gei, ext_drive, + afferent_exc_fraction, + Gl, Cm, El, + muV, muV0,DmuV0, + sV, sV0, DsV0, + muGn, + TvN, TvN0, DTvN0, + Vthre, Fout_th) Vthre_params_Ve = Vthre_params_vi = mathsbox = Mathsbox(sample, err_func) @@ -167,7 +167,7 @@ def __init__(self, model_name="meanfield_model_cond", binary="meanfield_model_cond.aplx", neuron_model=neuron_model, - config=config, + params_from_network=params_from_network, Vthre_params_Ve = , #PUT HERE Vthre_params_vi = , #PUT HERE mathsbox=mathsbox, diff --git a/spynnaker/pyNN/models/neuron/implementations/meanfield_impl_standard.py b/spynnaker/pyNN/models/neuron/implementations/meanfield_impl_standard.py index 78de61be3d1..380e207fcae 100644 --- a/spynnaker/pyNN/models/neuron/implementations/meanfield_impl_standard.py +++ b/spynnaker/pyNN/models/neuron/implementations/meanfield_impl_standard.py @@ -37,7 +37,7 @@ class MeanfieldImplStandard(AbstractNeuronImpl): "__model_name", "__binary", "__neuron_model", - "__config", + "__params_from_network", "__mathsbox", "__input_type", "__synapse_type", @@ -66,7 +66,8 @@ class MeanfieldImplStandard(AbstractNeuronImpl): } def __init__( - self, model_name, binary, neuron_model, config, mathsbox, + self, model_name, binary, neuron_model, + params_from_network, mathsbox, input_type, synapse_type, threshold_type, additional_input_type=None): """ @@ -82,7 +83,7 @@ def __init__( self.__model_name = model_name self.__binary = binary self.__neuron_model = neuron_model - self.__config = config + self.__params_from_network = params_from_network self.__mathsbox = mathsbox self.__input_type = input_type self.__synapse_type = synapse_type @@ -91,7 +92,7 @@ def __init__( self.__n_steps_per_timestep = _DEFAULT_N_STEPS_PER_TIMESTEP self.__components = [ - self.__neuron_model, self.__config, self.__mathsbox, + self.__neuron_model, self.__params_from_network, self.__mathsbox, self.__input_type, self.__threshold_type, self.__synapse_type] if self.__additional_input_type is not None: self.__components.append(self.__additional_input_type) @@ -118,7 +119,7 @@ def binary_name(self): def get_n_cpu_cycles(self, n_neurons): total = self.__neuron_model.get_n_cpu_cycles(n_neurons) total += self.__synapse_type.get_n_cpu_cycles(n_neurons) - total += self.__config.get_n_cpu_cycles(n_neurons) + total += self.__params_from_network.get_n_cpu_cycles(n_neurons) total += self.__input_type.get_n_cpu_cycles(n_neurons) total += self.__mathsbox.get_n_cpu_cycles(n_neurons) total += self.__threshold_type.get_n_cpu_cycles(n_neurons) @@ -131,7 +132,7 @@ def get_dtcm_usage_in_bytes(self, n_neurons): total = _N_STEPS_PER_TIMESTEP_SIZE total += self.__neuron_model.get_dtcm_usage_in_bytes(n_neurons) total += self.__synapse_type.get_dtcm_usage_in_bytes(n_neurons) - total += self.__config.get_dtcm_usage_in_bytes(n_neurons) + total += self.__params_from_network.get_dtcm_usage_in_bytes(n_neurons) total += self.__input_type.get_dtcm_usage_in_bytes(n_neurons) total += self.__mathsbox.get_dtcm_usage_in_bytes(n_neurons) total += self.__threshold_type.get_dtcm_usage_in_bytes(n_neurons) @@ -145,7 +146,7 @@ def get_sdram_usage_in_bytes(self, n_neurons): total = _N_STEPS_PER_TIMESTEP_SIZE total += self.__neuron_model.get_sdram_usage_in_bytes(n_neurons) total += self.__synapse_type.get_sdram_usage_in_bytes(n_neurons) - total += self.__config.get_sdram_usage_in_bytes(n_neurons) + total += self.__params_from_network.get_sdram_usage_in_bytes(n_neurons) total += self.__input_type.get_sdram_usage_in_bytes(n_neurons) total += self.__mathsbox.get_sdram_usage_in_bytes(n_neurons) total += self.__threshold_type.get_sdram_usage_in_bytes(n_neurons) diff --git a/spynnaker/pyNN/models/neuron/neuron_models/config.py b/spynnaker/pyNN/models/neuron/neuron_models/params_from_network.py similarity index 99% rename from spynnaker/pyNN/models/neuron/neuron_models/config.py rename to spynnaker/pyNN/models/neuron/neuron_models/params_from_network.py index 64658f26c46..0aadbfb2726 100644 --- a/spynnaker/pyNN/models/neuron/neuron_models/config.py +++ b/spynnaker/pyNN/models/neuron/neuron_models/params_from_network.py @@ -113,7 +113,7 @@ } -class Config(AbstractInputType): +class ParamsFromNetwork(AbstractInputType): """ Model of neuron due to Eugene M. Izhikevich et al """ __slots__ = [ From 43621b6e09f0f74f8d3c634550a97162cde4f5f8 Mon Sep 17 00:00:00 2001 From: Garandel Date: Tue, 26 Oct 2021 14:18:37 +0000 Subject: [PATCH 31/44] modified: abstract_pynn_meanfield_model_standard.py modified: builds/meanfield_base.py new file: neuron_models/p_fit_polynomial.py modified: neuron_models/params_from_network.py add an other struct file to implemente params from fit of single neuron for Vthre polynome --- .../abstract_pynn_meanfield_model_standard.py | 4 +- .../models/neuron/builds/meanfield_base.py | 36 +-- .../neuron/neuron_models/p_fit_polynomial.py | 214 ++++++++++++++++++ .../neuron_models/params_from_network.py | 150 +----------- 4 files changed, 238 insertions(+), 166 deletions(-) create mode 100644 spynnaker/pyNN/models/neuron/neuron_models/p_fit_polynomial.py diff --git a/spynnaker/pyNN/models/neuron/abstract_pynn_meanfield_model_standard.py b/spynnaker/pyNN/models/neuron/abstract_pynn_meanfield_model_standard.py index 1d608fff2d8..c10e41de32e 100644 --- a/spynnaker/pyNN/models/neuron/abstract_pynn_meanfield_model_standard.py +++ b/spynnaker/pyNN/models/neuron/abstract_pynn_meanfield_model_standard.py @@ -33,7 +33,7 @@ class AbstractPyNNMeanfieldModelStandard(AbstractPyNNNeuronModel): def __init__( self, model_name, binary, neuron_model, - params_from_network, Vthre_params_Ve, Vthre_params_Vi, + params_from_network, p_fit_polynomial_exc, p_fit_polynomial_inh, mathsbox, input_type, synapse_type, threshold_type, additional_input_type=None): """ @@ -51,7 +51,7 @@ def __init__( """ super().__init__(MeanfieldImplStandard( model_name, binary, neuron_model, - params_from_network, #PUT HERE + params_from_network, p_fit_polynomial_exc, p_fit_polynomial_inh, mathsbox, input_type, synapse_type, threshold_type, additional_input_type)) diff --git a/spynnaker/pyNN/models/neuron/builds/meanfield_base.py b/spynnaker/pyNN/models/neuron/builds/meanfield_base.py index 85760110706..5cf30ac8c3b 100644 --- a/spynnaker/pyNN/models/neuron/builds/meanfield_base.py +++ b/spynnaker/pyNN/models/neuron/builds/meanfield_base.py @@ -101,17 +101,17 @@ def __init__(self, Cm=200., El=-70., - p0=-0.0515518, - p1=0.00455197, - p2=-0.00760625, - p3=0.00094851, - p4=0.001, - p5=-0.0009863, - p6=-0.0026474, - p7=-0.0135417, - p8=0.0028742, - p9=0.0029213, - p10=-0.014084, + p0_exc=-0.0515518, + p1_exc=0.00455197, + p2_exc=-0.00760625, + p3_exc=0.00094851, + p4_exc=0.001, + p5_exc=-0.0009863, + p6_exc=-0.0026474, + p7_exc=-0.0135417, + p8_exc=0.0028742, + p9_exc=0.0029213, + p10_exc=-0.014084, muV=0., muV0=-0.06, @@ -155,8 +155,14 @@ def __init__(self, muGn, TvN, TvN0, DTvN0, Vthre, Fout_th) - Vthre_params_Ve = - Vthre_params_vi = + p_fit_polynomial_exc = pFitPolynomial(p0_exc, p1_exc, p2_exc, + p3_exc, p4_exc, p5_exc, + p6_exc, p7_exc, p8_exc, + p9_exc, p10_exc) + p_fit_polynomial_inh = pFitPolynomial(p0_inh, p1_inh, p2_inh, + p3_inh, p4_inh, p5_inh, + p6_inh, p7_inh, p8_inh, + p9_inh, p10_inh) mathsbox = Mathsbox(sample, err_func) synapse_type = SynapseTypeExponential( tau_syn_E, tau_syn_I, isyn_exc, isyn_inh) @@ -168,8 +174,8 @@ def __init__(self, binary="meanfield_model_cond.aplx", neuron_model=neuron_model, params_from_network=params_from_network, - Vthre_params_Ve = , #PUT HERE - Vthre_params_vi = , #PUT HERE + p_fit_polynomial_exc = , #PUT HERE + p_fit_polynomial_inh = , #PUT HERE mathsbox=mathsbox, input_type=input_type, synapse_type=synapse_type, diff --git a/spynnaker/pyNN/models/neuron/neuron_models/p_fit_polynomial.py b/spynnaker/pyNN/models/neuron/neuron_models/p_fit_polynomial.py new file mode 100644 index 00000000000..927165962f0 --- /dev/null +++ b/spynnaker/pyNN/models/neuron/neuron_models/p_fit_polynomial.py @@ -0,0 +1,214 @@ +# Copyright (c) 2017-2019 The University of Manchester +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +from spinn_utilities.overrides import overrides +from data_specification.enums import DataType +from spinn_front_end_common.utilities.constants import ( + MICRO_TO_MILLISECOND_CONVERSION) +from .abstract_neuron_model import AbstractNeuronModel +from .abstract_input_type import AbstractInputType +from spynnaker.pyNN.models.neuron.implementations import ( + AbstractStandardNeuronComponent) + +###--transfert function inputs from 'data_test/'+NRN1+'_'+NTWK+'_fit.npy' --### +P0 = "p0" +P1 = "p1" +P2 = "p2" +P3 = "p3" +P4 = "p4" +P5 = "p5" +P6 = "p6" +P7 = "p7" +P8 = "p8" +P9 = "p9" +P10 = "p10" + +UNITS = { + P0 : "", + P1 : "", + P2 : "", + P3 : "", + P4 : "", + P5 : "", + P6 : "", + P7 : "", + P8 : "", + P9 : "", + P10 : "", +} + + +class pFitPolynomial(AbstractInputType): + """ Model of neuron due to Eugene M. Izhikevich et al + """ + __slots__ = [ + "_p0", "_p1", "_p2", "_p3", "_p4", "_p5", + "_p6", "_p7", "_p8", "_p9", "_p10" + ] + + def __init__(self, + p0, p1, p2, p3, p4, p5, + p6, p7, p8, p9, p10,): + """ + :param a: :math:`a` + :type a: float, iterable(float), ~pyNN.random.RandomDistribution or + (mapping) function + + """ + super().__init__( + + [###--TF inputs--### + DataType.S031, #p0 + DataType.S031, #p1 + DataType.S031, #p2 + DataType.S031, #p3 + DataType.S031, #p4 + DataType.S031, #p5 + DataType.S031, #p6 + DataType.S031, #p7 + DataType.S031, #p8 + DataType.S031, #p9 + DataType.S031]) #p10 + + self._p0 = p0 + self._p1 = p1 + self._p2 = p2 + self._p3 = p3 + self._p4 = p4 + self._p5 = p5 + self._p6 = p6 + self._p7 = p7 + self._p8 = p8 + self._p9 = p9 + self._p10 = p10 + + @overrides(AbstractStandardNeuronComponent.get_n_cpu_cycles) + def get_n_cpu_cycles(self, n_neurons): + # A bit of a guess + return 150 * n_neurons + + @overrides(AbstractStandardNeuronComponent.add_parameters) + def add_parameters(self, parameters): + ###--TF inputs--### + parameters[P0] = self._p0 + parameters[P1] = self._p1 + parameters[P2] = self._p2 + parameters[P3] = self._p3 + parameters[P4] = self._p4 + parameters[P5] = self._p5 + parameters[P6] = self._p6 + parameters[P7] = self._p7 + parameters[P8] = self._p8 + parameters[P9] = self._p9 + parameters[P10] = self._p10 + + @overrides(AbstractStandardNeuronComponent.add_state_variables) + def add_state_variables(self, state_variables): + pass + @overrides(AbstractStandardNeuronComponent.get_units) + def get_units(self, variable): + return UNITS[variable] + + @overrides(AbstractStandardNeuronComponent.has_variable) + def has_variable(self, variable): + return variable in UNITS + + @overrides(AbstractNeuronModel.get_global_values) + def get_global_values(self, ts): + # pylint: disable=arguments-differ + pass + + @overrides(AbstractStandardNeuronComponent.get_values) + def get_values(self, parameters, state_variables, vertex_slice, ts): + """ + :param ts: machine time step + """ + # pylint: disable=arguments-differ + + # Add the rest of the data + return [parameters[P0],#TF input + parameters[P1], + parameters[P2], + parameters[P3], + parameters[P4], + parameters[P5], + parameters[P6], + parameters[P7], + parameters[P8], + parameters[P9], + parameters[P10] + ] + + @overrides(AbstractStandardNeuronComponent.update_values) + def update_values(self, values, parameters, state_variables): + + # Decode the values + (_p0, _p1, _p2, _p3, _p4, + _p5, _p6, _p7, _p8, _p9, _p10) = values + + @overrides(AbstractInputType.get_global_weight_scale) + def get_global_weight_scale(self): + return 1024.0 + +################### +###--TF inputs--### +################### + + @property + def p0(self): + return self._p0 + + @property + def p1(self): + return self._p1 + + @property + def p2(self): + return self._p2 + + @property + def p3(self): + return self._p3 + + @property + def p4(self): + return self._p4 + + @property + def p5(self): + return self._p5 + + @property + def p6(self): + return self._p6 + + @property + def p6(self): + return self._p6 + + @property + def p7(self): + return self._p7 + + @property + def p8(self): + return self._p8 + + @property + def p9(self): + return self._p9 + + @property + def p10(self): + return self._p10 diff --git a/spynnaker/pyNN/models/neuron/neuron_models/params_from_network.py b/spynnaker/pyNN/models/neuron/neuron_models/params_from_network.py index 0aadbfb2726..03aa478e129 100644 --- a/spynnaker/pyNN/models/neuron/neuron_models/params_from_network.py +++ b/spynnaker/pyNN/models/neuron/neuron_models/params_from_network.py @@ -38,19 +38,6 @@ CM = "Cm" EL = "El" -###--transfert function inputs from 'data_test/'+NRN1+'_'+NTWK+'_fit.npy' --### -P0 = "p0" -P1 = "p1" -P2 = "p2" -P3 = "p3" -P4 = "p4" -P5 = "p5" -P6 = "p6" -P7 = "p7" -P8 = "p8" -P9 = "p9" -P10 = "p10" - MUV = "muV" MUV0 = "muV0" DMUV0 = "DmuV0" @@ -85,18 +72,6 @@ GL: "Gl", CM: "pF", EL: "mV", - #TF inputs - P0 : "", - P1 : "", - P2 : "", - P3 : "", - P4 : "", - P5 : "", - P6 : "", - P7 : "", - P8 : "", - P9 : "", - P10 : "", VTHRE: "mV", MUV : "", MUV0 : "", @@ -121,8 +96,6 @@ class ParamsFromNetwork(AbstractInputType): "_Erev_exc", "_Erev_inh", "_Ntot", "_gei", "_ext_drive", "_afferent_exc_fraction", "_Gl", "_Cm", "_El", - "_p0", "_p1", "_p2", "_p3", "_p4", "_p5", - "_p6", "_p7", "_p8", "_p9", "_p10", "_Vthre", "_muV", "_muV0", "_DmuV0", "_sV", "_sV0", "_DsV0", "_muGn", "_TvN", "_TvN0", "_DTvN0", "_Vthre", "_Fout_th", ] @@ -145,27 +118,7 @@ def __init__(self, pconnec, :param a: :math:`a` :type a: float, iterable(float), ~pyNN.random.RandomDistribution or (mapping) function - :param b: :math:`b` - :type b: float, iterable(float), ~pyNN.random.RandomDistribution or - (mapping) function - :param c: :math:`c` - :type c: float, iterable(float), ~pyNN.random.RandomDistribution or - (mapping) function - :param d: :math:`d` - :type d: float, iterable(float), ~pyNN.random.RandomDistribution or - (mapping) function - :param v_init: :math:`v_{init}` - :type v_init: - float, iterable(float), ~pyNN.random.RandomDistribution or - (mapping) function - :param u_init: :math:`u_{init}` - :type u_init: - float, iterable(float), ~pyNN.random.RandomDistribution or - (mapping) function - :param i_offset: :math:`I_{offset}` - :type i_offset: - float, iterable(float), ~pyNN.random.RandomDistribution or - (mapping) function + """ super().__init__( @@ -184,18 +137,6 @@ def __init__(self, pconnec, DataType.S1615, #Gm DataType.S1615, #Cl DataType.S1615, #El - ###--TF inputs--### - DataType.S031, #p0 - DataType.S031, #p1 - DataType.S031, #p2 - DataType.S031, #p3 - DataType.S031, #p4 - DataType.S031, #p5 - DataType.S031, #p6 - DataType.S031, #p7 - DataType.S031, #p8 - DataType.S031, #p9 - DataType.S031, #p10 DataType.S1615, # muV DataType.S1615, # muV0 DataType.S1615, # DmuV0 @@ -223,17 +164,6 @@ def __init__(self, pconnec, self._Gl = Gl self._Cm = Cm self._El = El - self._p0 = p0 - self._p1 = p1 - self._p2 = p2 - self._p3 = p3 - self._p4 = p4 - self._p5 = p5 - self._p6 = p6 - self._p7 = p7 - self._p8 = p8 - self._p9 = p9 - self._p10 = p10 self._muV = muV self._muV0 = muV0 self._DmuV0 = DmuV0 @@ -269,18 +199,6 @@ def add_parameters(self, parameters): parameters[GL] = self._Gl parameters[CM] = self._Cm parameters[EL] = self._El - ###--TF inputs--### - parameters[P0] = self._p0 - parameters[P1] = self._p1 - parameters[P2] = self._p2 - parameters[P3] = self._p3 - parameters[P4] = self._p4 - parameters[P5] = self._p5 - parameters[P6] = self._p6 - parameters[P7] = self._p7 - parameters[P8] = self._p8 - parameters[P9] = self._p9 - parameters[P10] = self._p10 #parameters[MUV] = self._muV parameters[MUV0] = self._muV0 parameters[DMUV0] = self._DmuV0 @@ -333,17 +251,6 @@ def get_values(self, parameters, state_variables, vertex_slice, ts): parameters[GL], parameters[CM], parameters[EL], - parameters[P0],#TF input - parameters[P1], - parameters[P2], - parameters[P3], - parameters[P4], - parameters[P5], - parameters[P6], - parameters[P7], - parameters[P8], - parameters[P9], - parameters[P10], state_variables[MUV], parameters[MUV0], parameters[DMUV0], @@ -366,8 +273,6 @@ def update_values(self, values, parameters, state_variables): _Erev_exc, _Erev_inh, _Ntot, _gei, _ext_drive, _afferent_exc_fraction, _Gl, _Cm, _El, - _p0, _p1, _p2, _p3, _p4, - _p5, _p6, _p7, _p8, _p9, _p10, muV, _muV0, _DmuV0, sV, _sV0, _DsV0, muGn, @@ -448,59 +353,6 @@ def Cm(self): @property def El(self): return self._El - -################### -###--TF inputs--### -################### - - @property - def p0(self): - return self._p0 - - @property - def p1(self): - return self._p1 - - @property - def p2(self): - return self._p2 - - @property - def p3(self): - return self._p3 - - @property - def p4(self): - return self._p4 - - @property - def p5(self): - return self._p5 - - @property - def p6(self): - return self._p6 - - @property - def p6(self): - return self._p6 - - @property - def p7(self): - return self._p7 - - @property - def p8(self): - return self._p8 - - @property - def p9(self): - return self._p9 - - @property - def p10(self): - return self._p10 - @property def muV(self): From 87c31204b7b5e2d3332820a013cf9e539919c07d Mon Sep 17 00:00:00 2001 From: Garandel Date: Wed, 27 Oct 2021 07:45:02 +0000 Subject: [PATCH 32/44] modified: ../../../src/meanfield/implementations/meanfield_impl_standard.h modified: ../../../src/meanfield/models/params_from_network.h modified: ../../../../spynnaker/pyNN/models/neuron/builds/meanfield_base.py modified: ../../../../spynnaker/pyNN/models/neuron/implementations/meanfield_impl_standard.py modified: ../../../../spynnaker/pyNN/models/neuron/neuron_models/__init__.py modified: ../../../../spynnaker/pyNN/models/neuron/neuron_models/p_fit_polynomial.py modified: ../../../../spynnaker/pyNN/models/neuron/neuron_models/params_from_network.py A priori meanfield_model_cond.dict says that I'm out of DTCM. That's why I get the error: "Population meanfield_model_cond does not have parameter p0" Go back to the past commit without inh implemented, just to see. --- .../implementations/meanfield_impl_standard.h | 9 +- .../meanfield/models/params_from_network.h | 5 -- .../models/neuron/builds/meanfield_base.py | 82 +++++++------------ .../meanfield_impl_standard.py | 15 +++- .../models/neuron/neuron_models/__init__.py | 5 +- .../neuron/neuron_models/p_fit_polynomial.py | 68 +++++++-------- .../neuron_models/params_from_network.py | 2 - 7 files changed, 87 insertions(+), 99 deletions(-) diff --git a/neural_modelling/src/meanfield/implementations/meanfield_impl_standard.h b/neural_modelling/src/meanfield/implementations/meanfield_impl_standard.h index c68bd5d7b15..d04cb15687f 100644 --- a/neural_modelling/src/meanfield/implementations/meanfield_impl_standard.h +++ b/neural_modelling/src/meanfield/implementations/meanfield_impl_standard.h @@ -432,10 +432,11 @@ static void neuron_impl_do_timestep_update( // additional_inputs, firing_rate); // update neuron parameters - state_t result = meanfield_model_state_update( - this_meanfield, pNetwork_types, - Pfit_exc_types, Pfit_inh_types, - mathsbox_types); + state_t result = meanfield_model_state_update(this_meanfield, + pNetwork_types, + Pfit_exc_types, + Pfit_inh_types, + mathsbox_types); // determine if a spike should occur bool spike_now = diff --git a/neural_modelling/src/meanfield/models/params_from_network.h b/neural_modelling/src/meanfield/models/params_from_network.h index a70b8f29bbd..ee5846a2b1f 100644 --- a/neural_modelling/src/meanfield/models/params_from_network.h +++ b/neural_modelling/src/meanfield/models/params_from_network.h @@ -3,11 +3,6 @@ #include "../../meanfield/models/meanfield_model.h" - -/*struct config_t; -typedef struct config_t config_t; -typedef struct config_t* config_t;*/ - typedef struct ParamsFromNetwork_t { // nominally 'fixed' parameters REAL pconnec; diff --git a/spynnaker/pyNN/models/neuron/builds/meanfield_base.py b/spynnaker/pyNN/models/neuron/builds/meanfield_base.py index 5cf30ac8c3b..b910b0f2069 100644 --- a/spynnaker/pyNN/models/neuron/builds/meanfield_base.py +++ b/spynnaker/pyNN/models/neuron/builds/meanfield_base.py @@ -16,6 +16,7 @@ from spynnaker.pyNN.models.neuron.input_types import InputTypeConductance from spynnaker.pyNN.models.neuron.neuron_models import MeanfieldModelEitn from spynnaker.pyNN.models.neuron.neuron_models import ParamsFromNetwork +from spynnaker.pyNN.models.neuron.neuron_models import pFitPolynomial from spynnaker.pyNN.models.neuron.neuron_models import Mathsbox from spynnaker.pyNN.models.neuron.synapse_types import SynapseTypeExponential from spynnaker.pyNN.models.neuron.threshold_types import ThresholdTypeStatic @@ -31,42 +32,6 @@ class MeanfieldBase(AbstractPyNNMeanfieldModelStandard): :param a: :math:`a` :type a: float, iterable(float), ~pyNN.random.RandomDistribution or (mapping) function - :param b: :math:`b` - :type b: float, iterable(float), ~pyNN.random.RandomDistribution - or (mapping) function - :param c: :math:`c` - :type c: float, iterable(float), ~pyNN.random.RandomDistribution - or (mapping) function - :param d: :math:`d` - :type d: float, iterable(float), ~pyNN.random.RandomDistribution - or (mapping) function - :param i_offset: :math:`I_{offset}` - :type i_offset: float, iterable(float), ~pyNN.random.RandomDistribution - or (mapping) function - :param u: :math:`u_{init} = \\delta V_{init}` - :type u: float, iterable(float), ~pyNN.random.RandomDistribution - or (mapping) function - :param v: :math:`v_{init} = V_{init}` - :type v: float, iterable(float), ~pyNN.random.RandomDistribution - or (mapping) function - :param tau_syn_E: :math:`\\tau^{syn}_e` - :type tau_syn_E: float, iterable(float), ~pyNN.random.RandomDistribution - or (mapping) function - :param tau_syn_I: :math:`\\tau^{syn}_i` - :type tau_syn_I: float, iterable(float), ~pyNN.random.RandomDistribution - or (mapping) function - :param e_rev_E: :math:`E^{rev}_e` - :type e_rev_E: float, iterable(float), ~pyNN.random.RandomDistribution - or (mapping) function - :param e_rev_I: :math:`E^{rev}_i` - :type e_rev_I: float, iterable(float), ~pyNN.random.RandomDistribution - or (mapping) function - :param isyn_exc: :math:`I^{syn}_e` - :type isyn_exc: float, iterable(float), ~pyNN.random.RandomDistribution - or (mapping) function - :param isyn_inh: :math:`I^{syn}_i` - :type isyn_inh: float, iterable(float), ~pyNN.random.RandomDistribution - or (mapping) function """ # noinspection PyPep8Naming @@ -100,18 +65,8 @@ def __init__(self, Gl=10., Cm=200., El=-70., - - p0_exc=-0.0515518, - p1_exc=0.00455197, - p2_exc=-0.00760625, - p3_exc=0.00094851, - p4_exc=0.001, - p5_exc=-0.0009863, - p6_exc=-0.0026474, - p7_exc=-0.0135417, - p8_exc=0.0028742, - p9_exc=0.0029213, - p10_exc=-0.014084, + + muV=0., muV0=-0.06, @@ -130,6 +85,31 @@ def __init__(self, Vthre=-50., Fout_th=0., + p0_exc=-0.0515518, + p1_exc=0.00455197, + p2_exc=-0.00760625, + p3_exc=0.00094851, + p4_exc=0.001, + p5_exc=-0.0009863, + p6_exc=-0.0026474, + p7_exc=-0.0135417, + p8_exc=0.0028742, + p9_exc=0.0029213, + p10_exc=-0.014084, + + p0_inh=-0.049683193394879956, + p1_inh=0.004122891837443331, + p2_inh=-0.005484937414333363, + p3_inh=-0.0013451469634945864, + p4_inh=0.001, + p5_inh=-0.0010458736523258204, + p6_inh=0.0030610187552845367, + p7_inh=-0.00844848145052594, + p8_inh=-0.0025716686439000045, + p9_inh=0.0017986248339644851, + p10_inh=-0.013829339299067179, + + tau_syn_E=5.0, tau_syn_I=5.0, e_rev_E=0.0, @@ -150,7 +130,7 @@ def __init__(self, Ntot, gei, ext_drive, afferent_exc_fraction, Gl, Cm, El, - muV, muV0,DmuV0, + muV, muV0, DmuV0, sV, sV0, DsV0, muGn, TvN, TvN0, DTvN0, @@ -174,8 +154,8 @@ def __init__(self, binary="meanfield_model_cond.aplx", neuron_model=neuron_model, params_from_network=params_from_network, - p_fit_polynomial_exc = , #PUT HERE - p_fit_polynomial_inh = , #PUT HERE + p_fit_polynomial_exc = p_fit_polynomial_exc, + p_fit_polynomial_inh = p_fit_polynomial_inh, mathsbox=mathsbox, input_type=input_type, synapse_type=synapse_type, diff --git a/spynnaker/pyNN/models/neuron/implementations/meanfield_impl_standard.py b/spynnaker/pyNN/models/neuron/implementations/meanfield_impl_standard.py index 380e207fcae..29667e31403 100644 --- a/spynnaker/pyNN/models/neuron/implementations/meanfield_impl_standard.py +++ b/spynnaker/pyNN/models/neuron/implementations/meanfield_impl_standard.py @@ -38,6 +38,8 @@ class MeanfieldImplStandard(AbstractNeuronImpl): "__binary", "__neuron_model", "__params_from_network", + "__p_fit_polynomial_exc", + "__p_fit_polynomial_inh", "__mathsbox", "__input_type", "__synapse_type", @@ -67,7 +69,10 @@ class MeanfieldImplStandard(AbstractNeuronImpl): def __init__( self, model_name, binary, neuron_model, - params_from_network, mathsbox, + params_from_network, + p_fit_polynomial_exc, + p_fit_polynomial_inh, + mathsbox, input_type, synapse_type, threshold_type, additional_input_type=None): """ @@ -84,6 +89,8 @@ def __init__( self.__binary = binary self.__neuron_model = neuron_model self.__params_from_network = params_from_network + self.__p_fit_polynomial_exc = p_fit_polynomial_exc + self.__p_fit_polynomial_inh = p_fit_polynomial_inh self.__mathsbox = mathsbox self.__input_type = input_type self.__synapse_type = synapse_type @@ -120,6 +127,8 @@ def get_n_cpu_cycles(self, n_neurons): total = self.__neuron_model.get_n_cpu_cycles(n_neurons) total += self.__synapse_type.get_n_cpu_cycles(n_neurons) total += self.__params_from_network.get_n_cpu_cycles(n_neurons) + total += self.__p_fit_polynomial_exc.get_n_cpu_cycles(n_neurons) + total += self.__p_fit_polynomial_inh.get_n_cpu_cycles(n_neurons) total += self.__input_type.get_n_cpu_cycles(n_neurons) total += self.__mathsbox.get_n_cpu_cycles(n_neurons) total += self.__threshold_type.get_n_cpu_cycles(n_neurons) @@ -133,6 +142,8 @@ def get_dtcm_usage_in_bytes(self, n_neurons): total += self.__neuron_model.get_dtcm_usage_in_bytes(n_neurons) total += self.__synapse_type.get_dtcm_usage_in_bytes(n_neurons) total += self.__params_from_network.get_dtcm_usage_in_bytes(n_neurons) + total += self.__p_fit_polynomial_exc.get_dtcm_usage_in_bytes(n_neurons) + total += self.__p_fit_polynomial_inh.get_dtcm_usage_in_bytes(n_neurons) total += self.__input_type.get_dtcm_usage_in_bytes(n_neurons) total += self.__mathsbox.get_dtcm_usage_in_bytes(n_neurons) total += self.__threshold_type.get_dtcm_usage_in_bytes(n_neurons) @@ -147,6 +158,8 @@ def get_sdram_usage_in_bytes(self, n_neurons): total += self.__neuron_model.get_sdram_usage_in_bytes(n_neurons) total += self.__synapse_type.get_sdram_usage_in_bytes(n_neurons) total += self.__params_from_network.get_sdram_usage_in_bytes(n_neurons) + total += self.__p_fit_polynomial_exc.get_sdram_usage_in_bytes(n_neurons) + total += self.__p_fit_polynomial_inh.get_sdram_usage_in_bytes(n_neurons) total += self.__input_type.get_sdram_usage_in_bytes(n_neurons) total += self.__mathsbox.get_sdram_usage_in_bytes(n_neurons) total += self.__threshold_type.get_sdram_usage_in_bytes(n_neurons) diff --git a/spynnaker/pyNN/models/neuron/neuron_models/__init__.py b/spynnaker/pyNN/models/neuron/neuron_models/__init__.py index 4bd31557a38..d2ff271ddcc 100644 --- a/spynnaker/pyNN/models/neuron/neuron_models/__init__.py +++ b/spynnaker/pyNN/models/neuron/neuron_models/__init__.py @@ -16,11 +16,12 @@ from .abstract_neuron_model import AbstractNeuronModel from .neuron_model_izh import NeuronModelIzh from .meanfield_model_eitn import MeanfieldModelEitn -from .config import Config +from .params_from_network import ParamsFromNetwork +from .p_fit_polynomial import pFitPolynomial from .mathsbox import Mathsbox from .neuron_model_leaky_integrate_and_fire import ( NeuronModelLeakyIntegrateAndFire) __all__ = ["AbstractNeuronModel", "NeuronModelIzh", "NeuronModelLeakyIntegrateAndFire", - "MeanfieldModelEitn", "Config", "Mathsbox"] + "MeanfieldModelEitn", "pFitPolynomial", "ParamsFromNetwork", "Mathsbox"] diff --git a/spynnaker/pyNN/models/neuron/neuron_models/p_fit_polynomial.py b/spynnaker/pyNN/models/neuron/neuron_models/p_fit_polynomial.py index 927165962f0..e45d6def6e6 100644 --- a/spynnaker/pyNN/models/neuron/neuron_models/p_fit_polynomial.py +++ b/spynnaker/pyNN/models/neuron/neuron_models/p_fit_polynomial.py @@ -22,7 +22,7 @@ AbstractStandardNeuronComponent) ###--transfert function inputs from 'data_test/'+NRN1+'_'+NTWK+'_fit.npy' --### -P0 = "p0" +P0 = "p0_exc" P1 = "p1" P2 = "p2" P3 = "p3" @@ -50,16 +50,16 @@ class pFitPolynomial(AbstractInputType): - """ Model of neuron due to Eugene M. Izhikevich et al + """ Model of neuron due to ... """ __slots__ = [ - "_p0", "_p1", "_p2", "_p3", "_p4", "_p5", - "_p6", "_p7", "_p8", "_p9", "_p10" + "__p0_exc", "__p1_exc", "__p2_exc", "__p3_exc", "__p4_exc", "__p5_exc", + "__p6_exc", "__p7_exc", "__p8_exc", "__p9_exc", "__p10_exc" ] def __init__(self, - p0, p1, p2, p3, p4, p5, - p6, p7, p8, p9, p10,): + p0_exc, p1_exc, p2_exc, p3_exc, p4_exc, p5_exc, + p6_exc, p7_exc, p8_exc, p9_exc, p10_exc): """ :param a: :math:`a` :type a: float, iterable(float), ~pyNN.random.RandomDistribution or @@ -81,17 +81,17 @@ def __init__(self, DataType.S031, #p9 DataType.S031]) #p10 - self._p0 = p0 - self._p1 = p1 - self._p2 = p2 - self._p3 = p3 - self._p4 = p4 - self._p5 = p5 - self._p6 = p6 - self._p7 = p7 - self._p8 = p8 - self._p9 = p9 - self._p10 = p10 + self.__p0_exc = p0_exc + self.__p1_exc = p1_exc + self.__p2_exc = p2_exc + self.__p3_exc = p3_exc + self.__p4_exc = p4_exc + self.__p5_exc = p5_exc + self.__p6_exc = p6_exc + self.__p7_exc = p7_exc + self.__p8_exc = p8_exc + self.__p9_exc = p9_exc + self.__p10_exc = p10_exc @overrides(AbstractStandardNeuronComponent.get_n_cpu_cycles) def get_n_cpu_cycles(self, n_neurons): @@ -101,17 +101,17 @@ def get_n_cpu_cycles(self, n_neurons): @overrides(AbstractStandardNeuronComponent.add_parameters) def add_parameters(self, parameters): ###--TF inputs--### - parameters[P0] = self._p0 - parameters[P1] = self._p1 - parameters[P2] = self._p2 - parameters[P3] = self._p3 - parameters[P4] = self._p4 - parameters[P5] = self._p5 - parameters[P6] = self._p6 - parameters[P7] = self._p7 - parameters[P8] = self._p8 - parameters[P9] = self._p9 - parameters[P10] = self._p10 + parameters[P0] = self.__p0_exc + parameters[P1] = self.__p1_exc + parameters[P2] = self.__p2_exc + parameters[P3] = self.__p3_exc + parameters[P4] = self.__p4_exc + parameters[P5] = self.__p5_exc + parameters[P6] = self.__p6_exc + parameters[P7] = self.__p7_exc + parameters[P8] = self.__p8_exc + parameters[P9] = self.__p9_exc + parameters[P10] = self.__p10_exc @overrides(AbstractStandardNeuronComponent.add_state_variables) def add_state_variables(self, state_variables): @@ -154,8 +154,8 @@ def get_values(self, parameters, state_variables, vertex_slice, ts): def update_values(self, values, parameters, state_variables): # Decode the values - (_p0, _p1, _p2, _p3, _p4, - _p5, _p6, _p7, _p8, _p9, _p10) = values + (__p0_exc, __p1_exc, __p2_exc, __p3_exc, __p4_exc, + __p5_exc, __p6_exc, __p7_exc, __p8_exc, __p9_exc, __p10_exc) = values @overrides(AbstractInputType.get_global_weight_scale) def get_global_weight_scale(self): @@ -166,15 +166,15 @@ def get_global_weight_scale(self): ################### @property - def p0(self): - return self._p0 + def p0_exc(self): + return self.__p0_exc @property - def p1(self): + def p1_exc(self): return self._p1 @property - def p2(self): + def p2_exc(self): return self._p2 @property diff --git a/spynnaker/pyNN/models/neuron/neuron_models/params_from_network.py b/spynnaker/pyNN/models/neuron/neuron_models/params_from_network.py index 03aa478e129..e416e7d987d 100644 --- a/spynnaker/pyNN/models/neuron/neuron_models/params_from_network.py +++ b/spynnaker/pyNN/models/neuron/neuron_models/params_from_network.py @@ -107,8 +107,6 @@ def __init__(self, pconnec, Ntot, gei, ext_drive, afferent_exc_fraction, Gl, Cm, El, - p0, p1, p2, p3, p4, p5, - p6, p7, p8, p9, p10, muV, muV0,DmuV0, sV, sV0, DsV0, muGn, From 12222e282104b7b24f51e0cfbec0303628c13121 Mon Sep 17 00:00:00 2001 From: Garandel Date: Wed, 27 Oct 2021 09:15:19 +0000 Subject: [PATCH 33/44] modified: ../../../../spynnaker/pyNN/models/neuron/builds/meanfield_base.py modified: ../../../../spynnaker/pyNN/models/neuron/implementations/meanfield_impl_standard.py renamed: ../../../../spynnaker/pyNN/models/neuron/neuron_models/p_fit_polynomial.py -> ../../../../spynnaker/pyNN/models/neuron/neuron_models/P_fit_polynomial_exc.py new file: ../../../../spynnaker/pyNN/models/neuron/neuron_models/P_fit_polynomial_inh.py modified: ../../../../spynnaker/pyNN/models/neuron/neuron_models/__init__.py CHECK POINT That's compile and work in virtual mode for c and python. ERROR : DIVBY0 when reel mode --- .../models/neuron/builds/meanfield_base.py | 7 +- .../meanfield_impl_standard.py | 10 +- ..._polynomial.py => P_fit_polynomial_exc.py} | 62 ++--- .../neuron_models/P_fit_polynomial_inh.py | 214 ++++++++++++++++++ .../models/neuron/neuron_models/__init__.py | 7 +- 5 files changed, 262 insertions(+), 38 deletions(-) rename spynnaker/pyNN/models/neuron/neuron_models/{p_fit_polynomial.py => P_fit_polynomial_exc.py} (88%) create mode 100644 spynnaker/pyNN/models/neuron/neuron_models/P_fit_polynomial_inh.py diff --git a/spynnaker/pyNN/models/neuron/builds/meanfield_base.py b/spynnaker/pyNN/models/neuron/builds/meanfield_base.py index b910b0f2069..afc35d76c37 100644 --- a/spynnaker/pyNN/models/neuron/builds/meanfield_base.py +++ b/spynnaker/pyNN/models/neuron/builds/meanfield_base.py @@ -16,7 +16,8 @@ from spynnaker.pyNN.models.neuron.input_types import InputTypeConductance from spynnaker.pyNN.models.neuron.neuron_models import MeanfieldModelEitn from spynnaker.pyNN.models.neuron.neuron_models import ParamsFromNetwork -from spynnaker.pyNN.models.neuron.neuron_models import pFitPolynomial +from spynnaker.pyNN.models.neuron.neuron_models import pFitPolynomialExc +from spynnaker.pyNN.models.neuron.neuron_models import pFitPolynomialInh from spynnaker.pyNN.models.neuron.neuron_models import Mathsbox from spynnaker.pyNN.models.neuron.synapse_types import SynapseTypeExponential from spynnaker.pyNN.models.neuron.threshold_types import ThresholdTypeStatic @@ -135,11 +136,11 @@ def __init__(self, muGn, TvN, TvN0, DTvN0, Vthre, Fout_th) - p_fit_polynomial_exc = pFitPolynomial(p0_exc, p1_exc, p2_exc, + p_fit_polynomial_exc = pFitPolynomialExc(p0_exc, p1_exc, p2_exc, p3_exc, p4_exc, p5_exc, p6_exc, p7_exc, p8_exc, p9_exc, p10_exc) - p_fit_polynomial_inh = pFitPolynomial(p0_inh, p1_inh, p2_inh, + p_fit_polynomial_inh = pFitPolynomialInh(p0_inh, p1_inh, p2_inh, p3_inh, p4_inh, p5_inh, p6_inh, p7_inh, p8_inh, p9_inh, p10_inh) diff --git a/spynnaker/pyNN/models/neuron/implementations/meanfield_impl_standard.py b/spynnaker/pyNN/models/neuron/implementations/meanfield_impl_standard.py index 29667e31403..3f21f01ed80 100644 --- a/spynnaker/pyNN/models/neuron/implementations/meanfield_impl_standard.py +++ b/spynnaker/pyNN/models/neuron/implementations/meanfield_impl_standard.py @@ -99,8 +99,14 @@ def __init__( self.__n_steps_per_timestep = _DEFAULT_N_STEPS_PER_TIMESTEP self.__components = [ - self.__neuron_model, self.__params_from_network, self.__mathsbox, - self.__input_type, self.__threshold_type, self.__synapse_type] + self.__neuron_model, + self.__params_from_network, + self.__p_fit_polynomial_exc, + self.__p_fit_polynomial_inh, + self.__mathsbox, + self.__input_type, + self.__threshold_type, + self.__synapse_type] if self.__additional_input_type is not None: self.__components.append(self.__additional_input_type) diff --git a/spynnaker/pyNN/models/neuron/neuron_models/p_fit_polynomial.py b/spynnaker/pyNN/models/neuron/neuron_models/P_fit_polynomial_exc.py similarity index 88% rename from spynnaker/pyNN/models/neuron/neuron_models/p_fit_polynomial.py rename to spynnaker/pyNN/models/neuron/neuron_models/P_fit_polynomial_exc.py index e45d6def6e6..1082dafcf21 100644 --- a/spynnaker/pyNN/models/neuron/neuron_models/p_fit_polynomial.py +++ b/spynnaker/pyNN/models/neuron/neuron_models/P_fit_polynomial_exc.py @@ -23,16 +23,16 @@ ###--transfert function inputs from 'data_test/'+NRN1+'_'+NTWK+'_fit.npy' --### P0 = "p0_exc" -P1 = "p1" -P2 = "p2" -P3 = "p3" -P4 = "p4" -P5 = "p5" -P6 = "p6" -P7 = "p7" -P8 = "p8" -P9 = "p9" -P10 = "p10" +P1 = "p1_exc" +P2 = "p2_exc" +P3 = "p3_exc" +P4 = "p4_exc" +P5 = "p5_exc" +P6 = "p6_exc" +P7 = "p7_exc" +P8 = "p8_exc" +P9 = "p9_exc" +P10 = "p10_exc" UNITS = { P0 : "", @@ -49,7 +49,7 @@ } -class pFitPolynomial(AbstractInputType): +class pFitPolynomialExc(AbstractInputType): """ Model of neuron due to ... """ __slots__ = [ @@ -171,44 +171,44 @@ def p0_exc(self): @property def p1_exc(self): - return self._p1 + return self._p1_exc @property def p2_exc(self): - return self._p2 + return self._p2_exc @property - def p3(self): - return self._p3 + def p3_exc(self): + return self._p3_exc @property - def p4(self): - return self._p4 + def p4_exc(self): + return self._p4_exc @property - def p5(self): - return self._p5 + def p5_exc(self): + return self._p5_exc @property - def p6(self): - return self._p6 + def p6_exc(self): + return self._p6_exc @property - def p6(self): - return self._p6 + def p6_exc(self): + return self._p6_exc @property - def p7(self): - return self._p7 + def p7_exc(self): + return self._p7_exc @property - def p8(self): - return self._p8 + def p8_exc(self): + return self._p8_exc @property - def p9(self): - return self._p9 + def p9_exc(self): + return self._p9_exc @property - def p10(self): - return self._p10 + def p10_exc(self): + return self._p10_exc diff --git a/spynnaker/pyNN/models/neuron/neuron_models/P_fit_polynomial_inh.py b/spynnaker/pyNN/models/neuron/neuron_models/P_fit_polynomial_inh.py new file mode 100644 index 00000000000..b831e2e4e33 --- /dev/null +++ b/spynnaker/pyNN/models/neuron/neuron_models/P_fit_polynomial_inh.py @@ -0,0 +1,214 @@ +# Copyright (c) 2017-2019 The University of Manchester +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +from spinn_utilities.overrides import overrides +from data_specification.enums import DataType +from spinn_front_end_common.utilities.constants import ( + MICRO_TO_MILLISECOND_CONVERSION) +from .abstract_neuron_model import AbstractNeuronModel +from .abstract_input_type import AbstractInputType +from spynnaker.pyNN.models.neuron.implementations import ( + AbstractStandardNeuronComponent) + +###--transfert function inputs from 'data_test/'+NRN1+'_'+NTWK+'_fit.npy' --### +P0 = "p0_inh" +P1 = "p1_inh" +P2 = "p2_inh" +P3 = "p3_inh" +P4 = "p4_inh" +P5 = "p5_inh" +P6 = "p6_inh" +P7 = "p7_inh" +P8 = "p8_inh" +P9 = "p9_inh" +P10 = "p10_inh" + +UNITS = { + P0 : "", + P1 : "", + P2 : "", + P3 : "", + P4 : "", + P5 : "", + P6 : "", + P7 : "", + P8 : "", + P9 : "", + P10 : "", +} + + +class pFitPolynomialInh(AbstractInputType): + """ Model of neuron due to ... + """ + __slots__ = [ + "__p0_inh", "__p1_inh", "__p2_inh", "__p3_inh", "__p4_inh", "__p5_inh", + "__p6_inh", "__p7_inh", "__p8_inh", "__p9_inh", "__p10_inh" + ] + + def __init__(self, + p0_inh, p1_inh, p2_inh, p3_inh, p4_inh, p5_inh, + p6_inh, p7_inh, p8_inh, p9_inh, p10_inh): + """ + :param a: :math:`a` + :type a: float, iterable(float), ~pyNN.random.RandomDistribution or + (mapping) function + + """ + super().__init__( + + [###--TF inputs--### + DataType.S031, #p0 + DataType.S031, #p1 + DataType.S031, #p2 + DataType.S031, #p3 + DataType.S031, #p4 + DataType.S031, #p5 + DataType.S031, #p6 + DataType.S031, #p7 + DataType.S031, #p8 + DataType.S031, #p9 + DataType.S031]) #p10 + + self.__p0_inh = p0_inh + self.__p1_inh = p1_inh + self.__p2_inh = p2_inh + self.__p3_inh = p3_inh + self.__p4_inh = p4_inh + self.__p5_inh = p5_inh + self.__p6_inh = p6_inh + self.__p7_inh = p7_inh + self.__p8_inh = p8_inh + self.__p9_inh = p9_inh + self.__p10_inh = p10_inh + + @overrides(AbstractStandardNeuronComponent.get_n_cpu_cycles) + def get_n_cpu_cycles(self, n_neurons): + # A bit of a guess + return 150 * n_neurons + + @overrides(AbstractStandardNeuronComponent.add_parameters) + def add_parameters(self, parameters): + ###--TF inputs--### + parameters[P0] = self.__p0_inh + parameters[P1] = self.__p1_inh + parameters[P2] = self.__p2_inh + parameters[P3] = self.__p3_inh + parameters[P4] = self.__p4_inh + parameters[P5] = self.__p5_inh + parameters[P6] = self.__p6_inh + parameters[P7] = self.__p7_inh + parameters[P8] = self.__p8_inh + parameters[P9] = self.__p9_inh + parameters[P10] = self.__p10_inh + + @overrides(AbstractStandardNeuronComponent.add_state_variables) + def add_state_variables(self, state_variables): + pass + @overrides(AbstractStandardNeuronComponent.get_units) + def get_units(self, variable): + return UNITS[variable] + + @overrides(AbstractStandardNeuronComponent.has_variable) + def has_variable(self, variable): + return variable in UNITS + + @overrides(AbstractNeuronModel.get_global_values) + def get_global_values(self, ts): + # pylint: disable=arguments-differ + pass + + @overrides(AbstractStandardNeuronComponent.get_values) + def get_values(self, parameters, state_variables, vertex_slice, ts): + """ + :param ts: machine time step + """ + # pylint: disable=arguments-differ + + # Add the rest of the data + return [parameters[P0],#TF input + parameters[P1], + parameters[P2], + parameters[P3], + parameters[P4], + parameters[P5], + parameters[P6], + parameters[P7], + parameters[P8], + parameters[P9], + parameters[P10] + ] + + @overrides(AbstractStandardNeuronComponent.update_values) + def update_values(self, values, parameters, state_variables): + + # Decode the values + (__p0_inh, __p1_inh, __p2_inh, __p3_inh, __p4_inh, + __p5_inh, __p6_inh, __p7_inh, __p8_inh, __p9_inh, __p10_inh) = values + + @overrides(AbstractInputType.get_global_weight_scale) + def get_global_weight_scale(self): + return 1024.0 + +################### +###--TF inputs--### +################### + + @property + def p0_inh(self): + return self.__p0_inh + + @property + def p1_inh(self): + return self._p1_inh + + @property + def p2_inh(self): + return self._p2_inh + + @property + def p3_inh(self): + return self._p3_inh + + @property + def p4_inh(self): + return self._p4_inh + + @property + def p5_inh(self): + return self._p5_inh + + @property + def p6_inh(self): + return self._p6_inh + + @property + def p6_inh(self): + return self._p6_inh + + @property + def p7_inh(self): + return self._p7_inh + + @property + def p8_inh(self): + return self._p8_inh + + @property + def p9_inh(self): + return self._p9_inh + + @property + def p10_inh(self): + return self._p10_inh diff --git a/spynnaker/pyNN/models/neuron/neuron_models/__init__.py b/spynnaker/pyNN/models/neuron/neuron_models/__init__.py index d2ff271ddcc..e50a080002a 100644 --- a/spynnaker/pyNN/models/neuron/neuron_models/__init__.py +++ b/spynnaker/pyNN/models/neuron/neuron_models/__init__.py @@ -17,11 +17,14 @@ from .neuron_model_izh import NeuronModelIzh from .meanfield_model_eitn import MeanfieldModelEitn from .params_from_network import ParamsFromNetwork -from .p_fit_polynomial import pFitPolynomial +from .P_fit_polynomial_exc import pFitPolynomialExc +from .P_fit_polynomial_inh import pFitPolynomialInh from .mathsbox import Mathsbox from .neuron_model_leaky_integrate_and_fire import ( NeuronModelLeakyIntegrateAndFire) __all__ = ["AbstractNeuronModel", "NeuronModelIzh", "NeuronModelLeakyIntegrateAndFire", - "MeanfieldModelEitn", "pFitPolynomial", "ParamsFromNetwork", "Mathsbox"] + "MeanfieldModelEitn", + "pFitPolynomialExc", "pFitPolynomialInh", + "ParamsFromNetwork", "Mathsbox"] From a8106eff49830d1471eb1f6f80af3abbc0043493 Mon Sep 17 00:00:00 2001 From: Garandel Date: Thu, 28 Oct 2021 09:20:29 +0000 Subject: [PATCH 34/44] modified: ../../../src/meanfield/models/meanfield_model_impl.c modified: ../../../../spynnaker/pyNN/models/neuron/builds/meanfield_base.py DIVBY0 error is solved, due to put state var in local but don't go back to struct so all the time 0. RESUME : - TF for exc and inh with - some name changed in the files and in variables WILL: - Change MeanfieldModelEitn in python - add adaptation W ODE - change Fout_th for W in output --- .../meanfield/models/meanfield_model_impl.c | 82 +++++++++++-------- .../models/neuron/builds/meanfield_base.py | 30 +++---- 2 files changed, 64 insertions(+), 48 deletions(-) diff --git a/neural_modelling/src/meanfield/models/meanfield_model_impl.c b/neural_modelling/src/meanfield/models/meanfield_model_impl.c index aabf6a4e54f..f27dcbf49ab 100644 --- a/neural_modelling/src/meanfield/models/meanfield_model_impl.c +++ b/neural_modelling/src/meanfield/models/meanfield_model_impl.c @@ -87,7 +87,7 @@ void error_function( REAL x, REAL factor, mathsbox_t *restrict mathsbox){ } -void threshold_func(ParamsFromNetwork_t *restrict pNetwork, pFitPolynomial_t *restrict pfit) +void threshold_func(ParamsFromNetwork_t *restrict pNetwork, pFitPolynomial_t *restrict Pfit) { /* threshold function coming from : @@ -120,17 +120,17 @@ void threshold_func(ParamsFromNetwork_t *restrict pNetwork, pFitPolynomial_t *re REAL Vthre = pNetwork->Vthre; //REAL Fout_th = pNetwork->Fout_th; - REAL P0 = pfit->P0; - REAL P1 = pfit->P1; - REAL P2 = pfit->P2; - REAL P3 = pfit->P3; - REAL P4 = pfit->P4; - REAL P5 = pfit->P5; - REAL P6 = pfit->P6; - REAL P7 = pfit->P7; - REAL P8 = pfit->P8; - REAL P9 = pfit->P9; - REAL P10 = pfit->P10; + REAL P0 = Pfit->P0; + REAL P1 = Pfit->P1; + REAL P2 = Pfit->P2; + REAL P3 = Pfit->P3; + REAL P4 = Pfit->P4; + REAL P5 = Pfit->P5; + REAL P6 = Pfit->P6; + REAL P7 = Pfit->P7; + REAL P8 = Pfit->P8; + REAL P9 = Pfit->P9; + REAL P10 = Pfit->P10; // + 0.\ //P4*np.log(muGn) @@ -171,10 +171,10 @@ void get_fluct_regime_varsup(REAL Ve, REAL Vi, ParamsFromNetwork_t *restrict pNe REAL Ee = pNetwork->Ee; REAL Cm = pNetwork->Cm; - REAL muV = pNetwork->muV; - REAL muGn = pNetwork->muGn; - REAL sV = pNetwork->sV; - REAL TvN = pNetwork->TvN; + //REAL muV = pNetwork->muV; + //REAL muGn = pNetwork->muGn; + //REAL sV = pNetwork->sV; + //REAL TvN = pNetwork->TvN; // here TOTAL (sum over synapses) excitatory and inhibitory input @@ -190,15 +190,15 @@ void get_fluct_regime_varsup(REAL Ve, REAL Vi, ParamsFromNetwork_t *restrict pNe muG += ACS_DBL_TINY; } - muV = (muGe*Ee + muGi*Ei + Gl*El)/muG; + pNetwork->muV = (muGe*Ee + muGi*Ei + Gl*El)/muG; - muGn = muG/Gl; + pNetwork->muGn = muG/Gl; Tm = Cm/muG; - Ue = Qe/muG*(Ee-muV); - Ui = Qi/muG*(Ei-muV); + Ue = Qe/muG*(Ee-pNetwork->muV); + Ui = Qi/muG*(Ei-pNetwork->muV); /* @@ -209,10 +209,12 @@ void get_fluct_regime_varsup(REAL Ve, REAL Vi, ParamsFromNetwork_t *restrict pNe |->sqrtk() ne fonctionne pas !!! */ - - sV = Fe*(Ue*Te)*(Ue*Te)/REAL_CONST(2.)/(Te+Tm)\ + + pNetwork->sV = Fe*(Ue*Te)*(Ue*Te)/REAL_CONST(2.)/(Te+Tm)\ + Fi*(Ti*Ui)*(Ti*Ui)/REAL_CONST(2.)/(Ti+Tm); + + if (FeTvN = Tv*Gl/Cm; + } @@ -240,11 +243,23 @@ void TF(REAL Ve, REAL Vi, pFitPolynomial_t *restrict Pfit, mathsbox_t *restrict mathsbox){ -//PUT comments HERE!!! +/* + State-variables are directly connected to the struct + parameters are put in local in order to make the code clear. + +*/ REAL limit; REAL argument; + + REAL Gl = pNetwork->Gl; + REAL Cm = pNetwork->Cm; + + + if (pNetwork->Fout_th != ZERO){ + pNetwork->Fout_th = ACS_DBL_TINY; + } if (Ve < ACS_DBL_TINY){ Ve += ACS_DBL_TINY; @@ -256,7 +271,7 @@ void TF(REAL Ve, REAL Vi, get_fluct_regime_varsup(Ve, Vi, pNetwork); threshold_func(pNetwork, Pfit); - limit = REAL_HALF(pNetwork->Gl/(pNetwork->TvN * pNetwork->Cm)); + limit = REAL_HALF(Gl/(pNetwork->TvN * Cm)); /* normalement sqrt: argument = (pNetwork->Vthre - pNetwork->muV)/sqrtk(REAL_CONST(2.))/pNetwork->sV; @@ -274,14 +289,14 @@ void TF(REAL Ve, REAL Vi, } */ - pNetwork->Fout_th = (HALF*pNetwork->Gl) * mathsbox->err_func / (pNetwork->Cm*pNetwork->TvN);// REAL ONE + pNetwork->Fout_th = (HALF*Gl) * mathsbox->err_func / (Cm*pNetwork->TvN);// REAL ONE //pNetwork->Fout_th = mathsbox->err_func ; //TEST if (pNetwork->Fout_th < ACS_DBL_TINY){ pNetwork->Fout_th += ACS_DBL_TINY; } - + } @@ -296,25 +311,24 @@ void RK2_midpoint_MF(REAL h, meanfield_t *meanfield, REAL T_inv = meanfield->Timescale_inv; - TF(lastVe, lastVi, meanfield, pNetwork, Pfit_exc, mathsbox); - REAL lastTF_Ve = pNetwork->Fout_th; + TF(lastVe, lastVi, meanfield, pNetwork, Pfit_exc, mathsbox); + REAL lastTF_exc = pNetwork->Fout_th; TF(lastVe, lastVi, meanfield, pNetwork, Pfit_inh, mathsbox); - REAL lastTF_Vi = pNetwork->Fout_th; + REAL lastTF_inh = pNetwork->Fout_th; //configVe stand for TF1 i.e TF for exitatory pop. SO configVi is for TF2 //In fact no configVe and configVi just config, all in the same file. - meanfield->Ve += lastVe + (REAL_HALF(lastTF_Ve - lastVe) * (REAL_CONST(2.0)-h) * h); + meanfield->Ve += lastVe + (REAL_HALF(lastTF_exc - lastVe) * (REAL_CONST(2.0)-h) * h); meanfield->Ve = meanfield->Ve * T_inv; - meanfield->Vi += lastVi + (REAL_HALF(lastTF_Vi - lastVi) * (REAL_CONST(2.0)-h) * h); + meanfield->Vi += lastVi + (REAL_HALF(lastTF_inh - lastVi) * (REAL_CONST(2.0)-h) * h); meanfield->Vi = meanfield->Vi * T_inv; - - + } diff --git a/spynnaker/pyNN/models/neuron/builds/meanfield_base.py b/spynnaker/pyNN/models/neuron/builds/meanfield_base.py index afc35d76c37..606657770c9 100644 --- a/spynnaker/pyNN/models/neuron/builds/meanfield_base.py +++ b/spynnaker/pyNN/models/neuron/builds/meanfield_base.py @@ -36,12 +36,14 @@ class MeanfieldBase(AbstractPyNNMeanfieldModelStandard): """ # noinspection PyPep8Naming - @default_initial_values({"Ve", "Vi", "muV", "sV", "muGn", "TvN", "Vthre", - "Fout_th", "err_func", "isyn_exc", "isyn_inh"}) + @default_initial_values({"Ve", "Vi", "Fout_th", + "muV", "sV", "muGn", + "TvN", "Vthre", + "err_func", "isyn_exc", "isyn_inh"}) def __init__(self, nbr=1, - a=0, - b=0, + a=0., + b=0., tauw=1., Trefrac=5.0, Vreset=-65., @@ -98,17 +100,17 @@ def __init__(self, p9_exc=0.0029213, p10_exc=-0.014084, - p0_inh=-0.049683193394879956, - p1_inh=0.004122891837443331, - p2_inh=-0.005484937414333363, - p3_inh=-0.0013451469634945864, + p0_inh=-0.0496832, + p1_inh=0.00412289, + p2_inh=-0.0054849, + p3_inh=-0.0013451, p4_inh=0.001, - p5_inh=-0.0010458736523258204, - p6_inh=0.0030610187552845367, - p7_inh=-0.00844848145052594, - p8_inh=-0.0025716686439000045, - p9_inh=0.0017986248339644851, - p10_inh=-0.013829339299067179, + p5_inh=-0.0010459, + p6_inh=0.00306102, + p7_inh=-0.0084485, + p8_inh=-0.0025717, + p9_inh=0.00179862, + p10_inh=-0.013830, tau_syn_E=5.0, From 4bbfae7a9ea79d165ba061c2db96cae4a8a2ba45 Mon Sep 17 00:00:00 2001 From: Garandel Date: Thu, 28 Oct 2021 11:35:06 +0000 Subject: [PATCH 35/44] modified: ../builds/meanfield_base.py modified: __init__.py renamed: meanfield_model_eitn.py -> meanfield_of_adex_network.py Change the name from meanfield_model_eitn.py to meanfield_of_adex_network.py --- spynnaker/pyNN/models/neuron/builds/meanfield_base.py | 8 ++++---- spynnaker/pyNN/models/neuron/neuron_models/__init__.py | 4 ++-- ...anfield_model_eitn.py => meanfield_of_adex_network.py} | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) rename spynnaker/pyNN/models/neuron/neuron_models/{meanfield_model_eitn.py => meanfield_of_adex_network.py} (99%) diff --git a/spynnaker/pyNN/models/neuron/builds/meanfield_base.py b/spynnaker/pyNN/models/neuron/builds/meanfield_base.py index 606657770c9..fc10352ebe8 100644 --- a/spynnaker/pyNN/models/neuron/builds/meanfield_base.py +++ b/spynnaker/pyNN/models/neuron/builds/meanfield_base.py @@ -14,7 +14,7 @@ # along with this program. If not, see . from spynnaker.pyNN.models.neuron.input_types import InputTypeConductance -from spynnaker.pyNN.models.neuron.neuron_models import MeanfieldModelEitn +from spynnaker.pyNN.models.neuron.neuron_models import MeanfieldOfAdexNetwork from spynnaker.pyNN.models.neuron.neuron_models import ParamsFromNetwork from spynnaker.pyNN.models.neuron.neuron_models import pFitPolynomialExc from spynnaker.pyNN.models.neuron.neuron_models import pFitPolynomialInh @@ -124,9 +124,9 @@ def __init__(self, sample=100, err_func=0.): # pylint: disable=too-many-arguments, too-many-locals - neuron_model = MeanfieldModelEitn(nbr, a, b, tauw, Trefrac, - Vreset, delta_v, ampnoise, - Timescale_inv, Ve, Vi) + neuron_model = MeanfieldOfAdexNetwork(nbr, a, b, tauw, Trefrac, + Vreset, delta_v, ampnoise, + Timescale_inv, Ve, Vi) params_from_network = ParamsFromNetwork(pconnec, q_exc, q_inh, Tsyn_exc, Tsyn_inh, Erev_exc, Erev_inh, diff --git a/spynnaker/pyNN/models/neuron/neuron_models/__init__.py b/spynnaker/pyNN/models/neuron/neuron_models/__init__.py index e50a080002a..92dbf1199e8 100644 --- a/spynnaker/pyNN/models/neuron/neuron_models/__init__.py +++ b/spynnaker/pyNN/models/neuron/neuron_models/__init__.py @@ -15,7 +15,7 @@ from .abstract_neuron_model import AbstractNeuronModel from .neuron_model_izh import NeuronModelIzh -from .meanfield_model_eitn import MeanfieldModelEitn +from .meanfield_of_adex_network import MeanfieldOfAdexNetwork from .params_from_network import ParamsFromNetwork from .P_fit_polynomial_exc import pFitPolynomialExc from .P_fit_polynomial_inh import pFitPolynomialInh @@ -25,6 +25,6 @@ __all__ = ["AbstractNeuronModel", "NeuronModelIzh", "NeuronModelLeakyIntegrateAndFire", - "MeanfieldModelEitn", + "MeanfieldOfAdexNetwork", "pFitPolynomialExc", "pFitPolynomialInh", "ParamsFromNetwork", "Mathsbox"] diff --git a/spynnaker/pyNN/models/neuron/neuron_models/meanfield_model_eitn.py b/spynnaker/pyNN/models/neuron/neuron_models/meanfield_of_adex_network.py similarity index 99% rename from spynnaker/pyNN/models/neuron/neuron_models/meanfield_model_eitn.py rename to spynnaker/pyNN/models/neuron/neuron_models/meanfield_of_adex_network.py index 107af533fd1..79d33cc5c73 100644 --- a/spynnaker/pyNN/models/neuron/neuron_models/meanfield_model_eitn.py +++ b/spynnaker/pyNN/models/neuron/neuron_models/meanfield_of_adex_network.py @@ -49,7 +49,7 @@ } -class MeanfieldModelEitn(AbstractNeuronModel): +class MeanfieldOfAdexNetwork(AbstractNeuronModel): """ Model of meanfield due to A.Destehexe et al """ __slots__ = [ From bc2dc01cf2d3ce5c73120c4892086f226726adca Mon Sep 17 00:00:00 2001 From: Garandel Date: Thu, 28 Oct 2021 12:08:17 +0000 Subject: [PATCH 36/44] modified: ../../../src/meanfield/implementations/meanfield_impl_standard.h modified: ../../../src/meanfield/models/meanfield_model_impl.c modified: ../../../src/meanfield/models/meanfield_model_impl.h modified: ../../../../spynnaker/pyNN/models/neuron/builds/meanfield_base.py modified: ../../../../spynnaker/pyNN/models/neuron/implementations/meanfield_impl_standard.py modified: ../../../../spynnaker/pyNN/models/neuron/neuron_models/meanfield_of_adex_network.py Add the structure for adaptation W, that's work but give non-sense results. Need to add a start value and the real ODE. --- .../implementations/meanfield_impl_standard.h | 8 ++-- .../meanfield/models/meanfield_model_impl.c | 7 ++- .../meanfield/models/meanfield_model_impl.h | 1 + .../models/neuron/builds/meanfield_base.py | 5 +- .../meanfield_impl_standard.py | 6 +-- .../meanfield_of_adex_network.py | 47 +++++++++---------- 6 files changed, 38 insertions(+), 36 deletions(-) diff --git a/neural_modelling/src/meanfield/implementations/meanfield_impl_standard.h b/neural_modelling/src/meanfield/implementations/meanfield_impl_standard.h index d04cb15687f..100b393c7e6 100644 --- a/neural_modelling/src/meanfield/implementations/meanfield_impl_standard.h +++ b/neural_modelling/src/meanfield/implementations/meanfield_impl_standard.h @@ -43,7 +43,7 @@ enum word_recording_indices { //! V (somatic potential) recording index VE_RECORDING_INDEX = 0, VI_RECORDING_INDEX = 1, - FOUT_TH_RECORDING_INDEX = 2, + W_RECORDING_INDEX = 2, //! Gsyn_exc (excitatory synaptic conductance/current) recording index GSYN_EXC_RECORDING_INDEX = 3, //! Gsyn_inh (excitatory synaptic conductance/current) recording index @@ -381,7 +381,7 @@ static void neuron_impl_do_timestep_update( state_t firing_rate_Vi = meanfield_model_get_firing_rate_Vi( this_meanfield); - state_t Fout_th = meanfield_model_get_Fout_th(pNetwork_types); + state_t adaptation_W = meanfield_model_get_adaptation_W(this_meanfield); // Get the exc and inh values from the synapses input_t exc_values[NUM_EXCITATORY_RECEPTORS]; @@ -415,7 +415,7 @@ static void neuron_impl_do_timestep_update( neuron_recording_record_accum( VI_RECORDING_INDEX, meanfield_index, firing_rate_Vi); neuron_recording_record_accum( - FOUT_TH_RECORDING_INDEX, meanfield_index, Fout_th); + W_RECORDING_INDEX, meanfield_index, adaptation_W); neuron_recording_record_accum( GSYN_EXC_RECORDING_INDEX, meanfield_index, total_exc); neuron_recording_record_accum( @@ -501,12 +501,14 @@ static void neuron_impl_store_neuron_parameters( next += n_words_needed(n_meanfields * sizeof(meanfield_t)); } + /* if (sizeof(ParamsFromNetwork_t)) { log_debug("writing input type parameters"); spin1_memcpy(&address[next], pNetwork_array, n_meanfields * sizeof(ParamsFromNetwork_t)); next += n_words_needed(n_meanfields * sizeof(ParamsFromNetwork_t)); } + */ } diff --git a/neural_modelling/src/meanfield/models/meanfield_model_impl.c b/neural_modelling/src/meanfield/models/meanfield_model_impl.c index f27dcbf49ab..af1f5caf54a 100644 --- a/neural_modelling/src/meanfield/models/meanfield_model_impl.c +++ b/neural_modelling/src/meanfield/models/meanfield_model_impl.c @@ -308,6 +308,7 @@ void RK2_midpoint_MF(REAL h, meanfield_t *meanfield, REAL lastVe = meanfield->Ve; REAL lastVi = meanfield->Vi; + REAL lastW = meanfield->W; REAL T_inv = meanfield->Timescale_inv; @@ -328,6 +329,8 @@ void RK2_midpoint_MF(REAL h, meanfield_t *meanfield, meanfield->Vi += lastVi + (REAL_HALF(lastTF_inh - lastVi) * (REAL_CONST(2.0)-h) * h); meanfield->Vi = meanfield->Vi * T_inv; + + meanfield->W += lastW; } @@ -438,8 +441,8 @@ state_t meanfield_model_get_firing_rate_Vi(const meanfield_t *meanfield) { return meanfield->Vi; } -state_t meanfield_model_get_Fout_th(const ParamsFromNetwork_t *pNetwork){ - return pNetwork->Fout_th; +state_t meanfield_model_get_adaptation_W(const meanfield_t *meanfield){ + return meanfield->W; } diff --git a/neural_modelling/src/meanfield/models/meanfield_model_impl.h b/neural_modelling/src/meanfield/models/meanfield_model_impl.h index 3e6cff7caea..a69757088c0 100644 --- a/neural_modelling/src/meanfield/models/meanfield_model_impl.h +++ b/neural_modelling/src/meanfield/models/meanfield_model_impl.h @@ -41,6 +41,7 @@ typedef struct meanfield_t { REAL Ve; REAL Vi; + REAL W; REAL this_h; diff --git a/spynnaker/pyNN/models/neuron/builds/meanfield_base.py b/spynnaker/pyNN/models/neuron/builds/meanfield_base.py index fc10352ebe8..15bd20ca032 100644 --- a/spynnaker/pyNN/models/neuron/builds/meanfield_base.py +++ b/spynnaker/pyNN/models/neuron/builds/meanfield_base.py @@ -36,7 +36,7 @@ class MeanfieldBase(AbstractPyNNMeanfieldModelStandard): """ # noinspection PyPep8Naming - @default_initial_values({"Ve", "Vi", "Fout_th", + @default_initial_values({"Ve", "Vi", "W", "Fout_th", "muV", "sV", "muGn", "TvN", "Vthre", "err_func", "isyn_exc", "isyn_inh"}) @@ -52,6 +52,7 @@ def __init__(self, Timescale_inv=0.5, Ve=9., Vi=23., + W=1., pconnec=0.05, q_exc=1.5, @@ -126,7 +127,7 @@ def __init__(self, # pylint: disable=too-many-arguments, too-many-locals neuron_model = MeanfieldOfAdexNetwork(nbr, a, b, tauw, Trefrac, Vreset, delta_v, ampnoise, - Timescale_inv, Ve, Vi) + Timescale_inv, Ve, Vi, W) params_from_network = ParamsFromNetwork(pconnec, q_exc, q_inh, Tsyn_exc, Tsyn_inh, Erev_exc, Erev_inh, diff --git a/spynnaker/pyNN/models/neuron/implementations/meanfield_impl_standard.py b/spynnaker/pyNN/models/neuron/implementations/meanfield_impl_standard.py index 3f21f01ed80..ebbe2cfe01f 100644 --- a/spynnaker/pyNN/models/neuron/implementations/meanfield_impl_standard.py +++ b/spynnaker/pyNN/models/neuron/implementations/meanfield_impl_standard.py @@ -49,12 +49,12 @@ class MeanfieldImplStandard(AbstractNeuronImpl): "__n_steps_per_timestep" ] - _RECORDABLES = ["Ve", "Vi", "Fout_th", "gsyn_exc", "gsyn_inh"] + _RECORDABLES = ["Ve", "Vi", "W", "gsyn_exc", "gsyn_inh"] _RECORDABLE_DATA_TYPES = { "Ve": DataType.S1615, "Vi": DataType.S1615, - "Fout_th": DataType.S1615, + "W": DataType.S1615, "gsyn_exc": DataType.S1615, "gsyn_inh": DataType.S1615 } @@ -62,7 +62,7 @@ class MeanfieldImplStandard(AbstractNeuronImpl): _RECORDABLE_UNITS = { 'Ve': 'mV', 'Vi': 'mV', - 'Fout_th': "uS", + 'W': "uS", 'gsyn_exc': "uS", 'gsyn_inh': "uS" } diff --git a/spynnaker/pyNN/models/neuron/neuron_models/meanfield_of_adex_network.py b/spynnaker/pyNN/models/neuron/neuron_models/meanfield_of_adex_network.py index 79d33cc5c73..1b270145966 100644 --- a/spynnaker/pyNN/models/neuron/neuron_models/meanfield_of_adex_network.py +++ b/spynnaker/pyNN/models/neuron/neuron_models/meanfield_of_adex_network.py @@ -32,6 +32,7 @@ TIMESCALE_INV = "Timescale_inv" VE = "Ve" VI = "Vi" +W = "W" UNITS = { ###--Meanfield--### @@ -46,6 +47,7 @@ TIMESCALE_INV: "Hz", VE: "Hz", VI: "Hz", + W: " ", } @@ -54,37 +56,18 @@ class MeanfieldOfAdexNetwork(AbstractNeuronModel): """ __slots__ = [ "_nbr", "_a", "_b", "_tauw", "_Trefrac", "_Vreset", "_delta_v", - "_ampnoise", "_Timescale_inv", "_Ve_init", "_Vi_init" + "_ampnoise", "_Timescale_inv", "_Ve_init", "_Vi_init", "_W_init", ] def __init__(self, nbr, a, b, tauw, Trefrac, Vreset, delta_v, - ampnoise, Timescale_inv, Ve_init, Vi_init): + ampnoise, Timescale_inv, + Ve_init, Vi_init, W_init): """ :param a: :math:`a` :type a: float, iterable(float), ~pyNN.random.RandomDistribution or (mapping) function - :param b: :math:`b` - :type b: float, iterable(float), ~pyNN.random.RandomDistribution or - (mapping) function - :param c: :math:`c` - :type c: float, iterable(float), ~pyNN.random.RandomDistribution or - (mapping) function - :param d: :math:`d` - :type d: float, iterable(float), ~pyNN.random.RandomDistribution or - (mapping) function - :param v_init: :math:`v_{init}` - :type v_init: - float, iterable(float), ~pyNN.random.RandomDistribution or - (mapping) function - :param u_init: :math:`u_{init}` - :type u_init: - float, iterable(float), ~pyNN.random.RandomDistribution or - (mapping) function - :param i_offset: :math:`I_{offset}` - :type i_offset: - float, iterable(float), ~pyNN.random.RandomDistribution or - (mapping) function + """ super().__init__( [DataType.UINT32, #nbr @@ -97,7 +80,8 @@ def __init__(self, nbr, a, b, tauw, DataType.S1615, #ampnoise DataType.S1615, #Timescale_inv DataType.S1615, #Ve - DataType.S1615, #Vi + DataType.S1615, #Vi + DataType.S1615, #W DataType.S1615], # this_h (= machine_time_step) [DataType.S1615]) # machine_time_step self._nbr = nbr @@ -111,6 +95,7 @@ def __init__(self, nbr, a, b, tauw, self._Timescale_inv = Timescale_inv self._Ve_init = Ve_init self._Vi_init = Vi_init + self._W_init = W_init @overrides(AbstractStandardNeuronComponent.get_n_cpu_cycles) def get_n_cpu_cycles(self, n_neurons): @@ -134,7 +119,8 @@ def add_parameters(self, parameters): def add_state_variables(self, state_variables): state_variables[VE] = self._Ve_init state_variables[VI] = self._Vi_init - + state_variables[W] = self._W_init + @overrides(AbstractStandardNeuronComponent.get_units) def get_units(self, variable): return UNITS[variable] @@ -163,6 +149,7 @@ def get_values(self, parameters, state_variables, vertex_slice, ts): parameters[TIMESCALE_INV], state_variables[VE], state_variables[VI], + state_variables[W], float(ts) / MICRO_TO_MILLISECOND_CONVERSION ] @@ -172,11 +159,12 @@ def update_values(self, values, parameters, state_variables): # Decode the values (_nbr, _a, _b, _tauw, _Trefrac, _Vreset, _delta_v, - _ampnoise, _Timescale_inv, Ve, Vi, _this_h) = values + _ampnoise, _Timescale_inv, Ve, Vi, W, _this_h) = values # Copy the changed data only state_variables[VE] = Ve state_variables[VI] = Vi + state_variables[W] = W #state_variables[U] = u ################ @@ -236,3 +224,10 @@ def Vi_init(self): """ return self._Vi_init + @property + def W_init(self): + """ Settable model parameter: :math:`V_{i}` + + :rtype: float + """ + return self._W_init From 81dfef14ea6bf516372a888395cbf0f24ff2a492 Mon Sep 17 00:00:00 2001 From: Garandel Date: Fri, 29 Oct 2021 17:49:23 +0000 Subject: [PATCH 37/44] modified: ../../../src/meanfield/models/meanfield_model_impl.c modified: ../../../../spynnaker/pyNN/models/neuron/builds/meanfield_base.py modified: ../../../../spynnaker/pyNN/models/neuron/neuron_models/meanfield_of_adex_network.py Correct some error but have an error when calculating EDO with RK2_midpoint. maybe "error" come from recorder.py and constant.py will do some test so if need come back here --- .../meanfield/models/meanfield_model_impl.c | 55 ++++++++++++++----- .../models/neuron/builds/meanfield_base.py | 6 +- .../meanfield_of_adex_network.py | 2 +- 3 files changed, 43 insertions(+), 20 deletions(-) diff --git a/neural_modelling/src/meanfield/models/meanfield_model_impl.c b/neural_modelling/src/meanfield/models/meanfield_model_impl.c index af1f5caf54a..6edb5732064 100644 --- a/neural_modelling/src/meanfield/models/meanfield_model_impl.c +++ b/neural_modelling/src/meanfield/models/meanfield_model_impl.c @@ -69,17 +69,17 @@ static inline void neuron_ode( ################################################################### */ -void error_function( REAL x, REAL factor, mathsbox_t *restrict mathsbox){ +void error_function( REAL x, REAL argument, mathsbox_t *restrict mathsbox){ //devra coder fonction powerof REAL dt = x/mathsbox->error_func_sample; REAL t; //REAL Pi = 3.1415927;// here was a k REAL two_over_sqrt_Pi = REAL_CONST(1.128379167); //APPROXIMATION - REAL Erfc = mathsbox->err_func; + REAL Erfc = 0.;//mathsbox->err_func; for(t=0; t<=x; t+=dt){ //Erfc += factor*(2/sqrtk(Pi))*expk(-(t*t)); // the real one overflowed ITCM - Erfc += factor*two_over_sqrt_Pi*expk(-(t*t)); //working like this one + Erfc += argument*two_over_sqrt_Pi*expk(-(t*t)); //working like this one } mathsbox->err_func = Erfc; @@ -149,7 +149,7 @@ void threshold_func(ParamsFromNetwork_t *restrict pNetwork, pFitPolynomial_t *re } -void get_fluct_regime_varsup(REAL Ve, REAL Vi, ParamsFromNetwork_t *restrict pNetwork) +void get_fluct_regime_varsup(REAL Ve, REAL Vi, REAL W, ParamsFromNetwork_t *restrict pNetwork) { REAL Fe; @@ -171,6 +171,8 @@ void get_fluct_regime_varsup(REAL Ve, REAL Vi, ParamsFromNetwork_t *restrict pNe REAL Ee = pNetwork->Ee; REAL Cm = pNetwork->Cm; + + //REAL muV = pNetwork->muV; //REAL muGn = pNetwork->muGn; //REAL sV = pNetwork->sV; @@ -181,7 +183,7 @@ void get_fluct_regime_varsup(REAL Ve, REAL Vi, ParamsFromNetwork_t *restrict pNe Fe = Ve * (REAL_CONST(1.)-gei)*pconnec*Ntot; // default is 1 !! Fi = Vi * gei*pconnec*Ntot; - muGe = Qe*Te*Ve; + muGe = Qe*Te*Ve; // normaly = Ve*Te*Qe*Ke with Ke = p*Nue what it is? muGi = Qi*Ti*Vi; muG = Gl+muGe+muGi; @@ -190,7 +192,7 @@ void get_fluct_regime_varsup(REAL Ve, REAL Vi, ParamsFromNetwork_t *restrict pNe muG += ACS_DBL_TINY; } - pNetwork->muV = (muGe*Ee + muGi*Ei + Gl*El)/muG; + pNetwork->muV = (muGe*Ee + muGi*Ei + Gl*El - W)/muG; pNetwork->muGn = muG/Gl; @@ -237,7 +239,7 @@ void get_fluct_regime_varsup(REAL Ve, REAL Vi, ParamsFromNetwork_t *restrict pNe } -void TF(REAL Ve, REAL Vi, +void TF(REAL Ve, REAL Vi, REAL W, meanfield_t *meanfield, ParamsFromNetwork_t *restrict pNetwork, pFitPolynomial_t *restrict Pfit, @@ -268,7 +270,7 @@ void TF(REAL Ve, REAL Vi, Vi += ACS_DBL_TINY; } - get_fluct_regime_varsup(Ve, Vi, pNetwork); + get_fluct_regime_varsup(Ve, Vi, W, pNetwork); threshold_func(pNetwork, Pfit); limit = REAL_HALF(Gl/(pNetwork->TvN * Cm)); @@ -280,7 +282,7 @@ void TF(REAL Ve, REAL Vi, if (pNetwork->sVsV += ACS_DBL_TINY; } - argument = (pNetwork->Vthre - pNetwork->muV)/(REAL_CONST(1.4142137))/pNetwork->sV; + argument = (pNetwork->Vthre - pNetwork->muV)/(REAL_CONST(1.4142137)*pNetwork->sV); error_function(limit, argument, mathsbox); /* @@ -309,28 +311,51 @@ void RK2_midpoint_MF(REAL h, meanfield_t *meanfield, REAL lastVe = meanfield->Ve; REAL lastVi = meanfield->Vi; REAL lastW = meanfield->W; + //REAL tauw = meanfield->tauw; + + //REAL W_tauw; REAL T_inv = meanfield->Timescale_inv; - TF(lastVe, lastVi, meanfield, pNetwork, Pfit_exc, mathsbox); + TF(lastVe, lastVi, lastW, meanfield, pNetwork, Pfit_exc, mathsbox); REAL lastTF_exc = pNetwork->Fout_th; - TF(lastVe, lastVi, meanfield, pNetwork, Pfit_inh, mathsbox); + TF(lastVe, lastVi, lastW, meanfield, pNetwork, Pfit_inh, mathsbox); REAL lastTF_inh = pNetwork->Fout_th; //configVe stand for TF1 i.e TF for exitatory pop. SO configVi is for TF2 //In fact no configVe and configVi just config, all in the same file. + /* + some trouble come from constants : + from spynnaker.pyNN.utilities.constants + + and + + pyNN/models/recorder.py + + */ - - meanfield->Ve += lastVe + (REAL_HALF(lastTF_exc - lastVe) * (REAL_CONST(2.0)-h) * h); + + REAL k1_exc = (lastTF_exc - lastVe)*T_inv; + REAL k2_exc = lastVe + h*k1_exc; + + meanfield->Ve += lastVe + REAL_HALF(h*(k1_exc + k2_exc))*REAL_CONST(0.5); + + //meanfield->Ve += lastVe + (REAL_HALF(lastTF_exc - lastVe) * (REAL_CONST(2.0)-h) * h); meanfield->Ve = meanfield->Ve * T_inv; meanfield->Vi += lastVi + (REAL_HALF(lastTF_inh - lastVi) * (REAL_CONST(2.0)-h) * h); - meanfield->Vi = meanfield->Vi * T_inv; + meanfield->Vi = meanfield->Vi * ONE; + + REAL k1_W = -lastW;//tauw; + REAL k2_W = -lastW*(ONE+h);//tauw; - meanfield->W += lastW; + //W_tauw = -lastW ;//+ meanfield->b*lastVe*meanfield->tauw + // + meanfield->a*(pNetwork->muV-pNetwork->El)*meanfield->tauw; + //meanfield->W += W_tauw ;/// meanfield->tauw ; + meanfield->W += lastW;//lastW + (h*(k1_W+k2_W)); } diff --git a/spynnaker/pyNN/models/neuron/builds/meanfield_base.py b/spynnaker/pyNN/models/neuron/builds/meanfield_base.py index 15bd20ca032..c9e9b29d88a 100644 --- a/spynnaker/pyNN/models/neuron/builds/meanfield_base.py +++ b/spynnaker/pyNN/models/neuron/builds/meanfield_base.py @@ -41,7 +41,7 @@ class MeanfieldBase(AbstractPyNNMeanfieldModelStandard): "TvN", "Vthre", "err_func", "isyn_exc", "isyn_inh"}) def __init__(self, - nbr=1, + nbr=1., a=0., b=0., tauw=1., @@ -52,7 +52,7 @@ def __init__(self, Timescale_inv=0.5, Ve=9., Vi=23., - W=1., + W=0.5, pconnec=0.05, q_exc=1.5, @@ -69,8 +69,6 @@ def __init__(self, Gl=10., Cm=200., El=-70., - - muV=0., muV0=-0.06, diff --git a/spynnaker/pyNN/models/neuron/neuron_models/meanfield_of_adex_network.py b/spynnaker/pyNN/models/neuron/neuron_models/meanfield_of_adex_network.py index 1b270145966..478106f1de1 100644 --- a/spynnaker/pyNN/models/neuron/neuron_models/meanfield_of_adex_network.py +++ b/spynnaker/pyNN/models/neuron/neuron_models/meanfield_of_adex_network.py @@ -47,7 +47,7 @@ TIMESCALE_INV: "Hz", VE: "Hz", VI: "Hz", - W: " ", + W: "mV ", } From d275a9c0619306b0998381d9fc6f2eb8f1ce8829 Mon Sep 17 00:00:00 2001 From: Garandel Date: Tue, 2 Nov 2021 15:06:43 +0000 Subject: [PATCH 38/44] modified: ../../../src/meanfield/models/meanfield_model_impl.c modified: ../../../src/meanfield/models/meanfield_model_impl.h modified: ../../../../spynnaker/pyNN/models/neuron/builds/meanfield_base.py modified: ../../../../spynnaker/pyNN/models/neuron/implementations/meanfield_impl_standard.py modified: ../../../../spynnaker/pyNN/models/neuron/neuron_models/meanfield_of_adex_network.py modified: ../../../../spynnaker/pyNN/models/recorder.py modified: ../../../../spynnaker/pyNN/utilities/constants.py do some modification aparently without effect of recorder and constant in rder to integrate Ve, Vi and W. Will modify meanfield_t because Vthre left in it but not anymore in meanfield_t and so modif meanfield_f_adex_network.py --- .../meanfield/models/meanfield_model_impl.c | 13 +++++++------ .../meanfield/models/meanfield_model_impl.h | 2 +- .../models/neuron/builds/meanfield_base.py | 8 ++++---- .../implementations/meanfield_impl_standard.py | 10 +++++----- .../neuron_models/meanfield_of_adex_network.py | 18 +++++++++--------- spynnaker/pyNN/models/recorder.py | 12 ++++++++---- spynnaker/pyNN/utilities/constants.py | 3 +++ 7 files changed, 37 insertions(+), 29 deletions(-) diff --git a/neural_modelling/src/meanfield/models/meanfield_model_impl.c b/neural_modelling/src/meanfield/models/meanfield_model_impl.c index 6edb5732064..dc8629b7d16 100644 --- a/neural_modelling/src/meanfield/models/meanfield_model_impl.c +++ b/neural_modelling/src/meanfield/models/meanfield_model_impl.c @@ -310,7 +310,7 @@ void RK2_midpoint_MF(REAL h, meanfield_t *meanfield, REAL lastVe = meanfield->Ve; REAL lastVi = meanfield->Vi; - REAL lastW = meanfield->W; + REAL lastW = meanfield->w; //REAL tauw = meanfield->tauw; //REAL W_tauw; @@ -327,7 +327,7 @@ void RK2_midpoint_MF(REAL h, meanfield_t *meanfield, //configVe stand for TF1 i.e TF for exitatory pop. SO configVi is for TF2 //In fact no configVe and configVi just config, all in the same file. /* - some trouble come from constants : + some troubles maybe come from constants : from spynnaker.pyNN.utilities.constants and @@ -347,15 +347,15 @@ void RK2_midpoint_MF(REAL h, meanfield_t *meanfield, meanfield->Vi += lastVi + (REAL_HALF(lastTF_inh - lastVi) * (REAL_CONST(2.0)-h) * h); - meanfield->Vi = meanfield->Vi * ONE; + meanfield->Vi = meanfield->Vi * ONE; //*T_inv normaly REAL k1_W = -lastW;//tauw; REAL k2_W = -lastW*(ONE+h);//tauw; //W_tauw = -lastW ;//+ meanfield->b*lastVe*meanfield->tauw // + meanfield->a*(pNetwork->muV-pNetwork->El)*meanfield->tauw; - //meanfield->W += W_tauw ;/// meanfield->tauw ; - meanfield->W += lastW;//lastW + (h*(k1_W+k2_W)); + meanfield->w += meanfield->tauw ; + //meanfield->w += lastW;///REAL_CONST(10.);//lastW + (h*(k1_W+k2_W)); } @@ -467,13 +467,14 @@ state_t meanfield_model_get_firing_rate_Vi(const meanfield_t *meanfield) { } state_t meanfield_model_get_adaptation_W(const meanfield_t *meanfield){ - return meanfield->W; + return meanfield->w; } void meanfield_model_print_state_variables(const meanfield_t *meanfield) { log_debug("Ve = %11.4k ", meanfield->Ve); log_debug("Vi = %11.4k ", meanfield->Vi); + log_debug("W = %11.4k ", meanfield->w); } void meanfield_model_print_parameters(const meanfield_t *meanfield) { diff --git a/neural_modelling/src/meanfield/models/meanfield_model_impl.h b/neural_modelling/src/meanfield/models/meanfield_model_impl.h index a69757088c0..85907918959 100644 --- a/neural_modelling/src/meanfield/models/meanfield_model_impl.h +++ b/neural_modelling/src/meanfield/models/meanfield_model_impl.h @@ -41,7 +41,7 @@ typedef struct meanfield_t { REAL Ve; REAL Vi; - REAL W; + REAL w; REAL this_h; diff --git a/spynnaker/pyNN/models/neuron/builds/meanfield_base.py b/spynnaker/pyNN/models/neuron/builds/meanfield_base.py index c9e9b29d88a..7e1ccd1c6ea 100644 --- a/spynnaker/pyNN/models/neuron/builds/meanfield_base.py +++ b/spynnaker/pyNN/models/neuron/builds/meanfield_base.py @@ -36,14 +36,14 @@ class MeanfieldBase(AbstractPyNNMeanfieldModelStandard): """ # noinspection PyPep8Naming - @default_initial_values({"Ve", "Vi", "W", "Fout_th", + @default_initial_values({"Ve", "Vi", "w", "Fout_th", "muV", "sV", "muGn", "TvN", "Vthre", "err_func", "isyn_exc", "isyn_inh"}) def __init__(self, nbr=1., a=0., - b=0., + b=1., tauw=1., Trefrac=5.0, Vreset=-65., @@ -52,7 +52,7 @@ def __init__(self, Timescale_inv=0.5, Ve=9., Vi=23., - W=0.5, + w=0.25, pconnec=0.05, q_exc=1.5, @@ -125,7 +125,7 @@ def __init__(self, # pylint: disable=too-many-arguments, too-many-locals neuron_model = MeanfieldOfAdexNetwork(nbr, a, b, tauw, Trefrac, Vreset, delta_v, ampnoise, - Timescale_inv, Ve, Vi, W) + Timescale_inv, Ve, Vi, w) params_from_network = ParamsFromNetwork(pconnec, q_exc, q_inh, Tsyn_exc, Tsyn_inh, Erev_exc, Erev_inh, diff --git a/spynnaker/pyNN/models/neuron/implementations/meanfield_impl_standard.py b/spynnaker/pyNN/models/neuron/implementations/meanfield_impl_standard.py index ebbe2cfe01f..eb7ac32c55c 100644 --- a/spynnaker/pyNN/models/neuron/implementations/meanfield_impl_standard.py +++ b/spynnaker/pyNN/models/neuron/implementations/meanfield_impl_standard.py @@ -49,20 +49,20 @@ class MeanfieldImplStandard(AbstractNeuronImpl): "__n_steps_per_timestep" ] - _RECORDABLES = ["Ve", "Vi", "W", "gsyn_exc", "gsyn_inh"] + _RECORDABLES = ["Ve", "Vi", "w", "gsyn_exc", "gsyn_inh"] _RECORDABLE_DATA_TYPES = { "Ve": DataType.S1615, "Vi": DataType.S1615, - "W": DataType.S1615, + "w": DataType.S1615, "gsyn_exc": DataType.S1615, "gsyn_inh": DataType.S1615 } _RECORDABLE_UNITS = { - 'Ve': 'mV', - 'Vi': 'mV', - 'W': "uS", + 'Ve': 'Hz', + 'Vi': 'Hz', + 'w': "pA", 'gsyn_exc': "uS", 'gsyn_inh': "uS" } diff --git a/spynnaker/pyNN/models/neuron/neuron_models/meanfield_of_adex_network.py b/spynnaker/pyNN/models/neuron/neuron_models/meanfield_of_adex_network.py index 478106f1de1..b4bac9dd57b 100644 --- a/spynnaker/pyNN/models/neuron/neuron_models/meanfield_of_adex_network.py +++ b/spynnaker/pyNN/models/neuron/neuron_models/meanfield_of_adex_network.py @@ -32,7 +32,7 @@ TIMESCALE_INV = "Timescale_inv" VE = "Ve" VI = "Vi" -W = "W" +W = "w" UNITS = { ###--Meanfield--### @@ -56,13 +56,13 @@ class MeanfieldOfAdexNetwork(AbstractNeuronModel): """ __slots__ = [ "_nbr", "_a", "_b", "_tauw", "_Trefrac", "_Vreset", "_delta_v", - "_ampnoise", "_Timescale_inv", "_Ve_init", "_Vi_init", "_W_init", + "_ampnoise", "_Timescale_inv", "_Ve_init", "_Vi_init", "_w_init", ] def __init__(self, nbr, a, b, tauw, Trefrac, Vreset, delta_v, ampnoise, Timescale_inv, - Ve_init, Vi_init, W_init): + Ve_init, Vi_init, w_init): """ :param a: :math:`a` :type a: float, iterable(float), ~pyNN.random.RandomDistribution or @@ -95,7 +95,7 @@ def __init__(self, nbr, a, b, tauw, self._Timescale_inv = Timescale_inv self._Ve_init = Ve_init self._Vi_init = Vi_init - self._W_init = W_init + self._w_init = w_init @overrides(AbstractStandardNeuronComponent.get_n_cpu_cycles) def get_n_cpu_cycles(self, n_neurons): @@ -119,7 +119,7 @@ def add_parameters(self, parameters): def add_state_variables(self, state_variables): state_variables[VE] = self._Ve_init state_variables[VI] = self._Vi_init - state_variables[W] = self._W_init + state_variables[W] = self._w_init @overrides(AbstractStandardNeuronComponent.get_units) def get_units(self, variable): @@ -159,12 +159,12 @@ def update_values(self, values, parameters, state_variables): # Decode the values (_nbr, _a, _b, _tauw, _Trefrac, _Vreset, _delta_v, - _ampnoise, _Timescale_inv, Ve, Vi, W, _this_h) = values + _ampnoise, _Timescale_inv, Ve, Vi, w, _this_h) = values # Copy the changed data only state_variables[VE] = Ve state_variables[VI] = Vi - state_variables[W] = W + state_variables[W] = w #state_variables[U] = u ################ @@ -225,9 +225,9 @@ def Vi_init(self): return self._Vi_init @property - def W_init(self): + def w_init(self): """ Settable model parameter: :math:`V_{i}` :rtype: float """ - return self._W_init + return self._w_init diff --git a/spynnaker/pyNN/models/recorder.py b/spynnaker/pyNN/models/recorder.py index 508322884dd..d50ebd97822 100644 --- a/spynnaker/pyNN/models/recorder.py +++ b/spynnaker/pyNN/models/recorder.py @@ -25,14 +25,16 @@ from spynnaker.pyNN.models.common import ( AbstractSpikeRecordable, AbstractNeuronRecordable, AbstractEventRecordable) from spynnaker.pyNN.utilities.constants import ( - SPIKES, MEMBRANE_POTENTIAL, GSYN_EXCIT, GSYN_INHIB, REWIRING) + SPIKES, FIRING_RATE_EXC, FIRING_RATE_INH, ADAPTATION, GSYN_EXCIT, GSYN_INHIB, REWIRING) from spynnaker.pyNN.exceptions import InvalidParameterType from spynnaker.pyNN.utilities.data_cache import DataCache logger = FormatAdapter(logging.getLogger(__name__)) _DEFAULT_UNITS = { SPIKES: "spikes", - MEMBRANE_POTENTIAL: "mV", + FIRING_RATE_EXC : 'Hz', + FIRING_RATE_INH : 'Hz', + ADAPTATION : 'pA',#MEMBRANE_POTENTIAL: "mV", GSYN_EXCIT: "uS", GSYN_INHIB: "uS", REWIRING: "ms"} @@ -62,9 +64,11 @@ def __init__(self, population, vertex): # file flags, allows separate files for the recorded variables self.__write_to_files_indicators = { 'spikes': None, + 'Ve' : None, + 'Vi' : None, + 'w' : None, 'gsyn_exc': None, - 'gsyn_inh': None, - 'v': None} + 'gsyn_inh': None} self._recording_start_time = get_simulator().t self._data_cache = {} diff --git a/spynnaker/pyNN/utilities/constants.py b/spynnaker/pyNN/utilities/constants.py index f84f631619c..60a9d22d1d1 100644 --- a/spynnaker/pyNN/utilities/constants.py +++ b/spynnaker/pyNN/utilities/constants.py @@ -62,6 +62,9 @@ # names for recording components SPIKES = 'spikes' +FIRING_RATE_EXC = 'Ve' +FIRING_RATE_INH = 'Vi' +ADAPTATION = 'w' MEMBRANE_POTENTIAL = "v" GSYN_EXCIT = "gsyn_exc" GSYN_INHIB = "gsyn_inh" From 199bd2301e85b6f8200e1aa35e8e99313cd305e1 Mon Sep 17 00:00:00 2001 From: Garandel Date: Tue, 2 Nov 2021 15:13:26 +0000 Subject: [PATCH 39/44] modified: ../../../src/meanfield/models/meanfield_model_impl.h modified: ../../../../spynnaker/pyNN/models/neuron/builds/meanfield_base.py modified: ../../../../spynnaker/pyNN/models/neuron/neuron_models/meanfield_of_adex_network.py remove nbr from meanfielf_t and to meanfield_of_adex_network.py --- .../meanfield/models/meanfield_model_impl.h | 1 - .../models/neuron/builds/meanfield_base.py | 3 +-- .../meanfield_of_adex_network.py | 21 ++++++++++--------- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/neural_modelling/src/meanfield/models/meanfield_model_impl.h b/neural_modelling/src/meanfield/models/meanfield_model_impl.h index 85907918959..ed057657fef 100644 --- a/neural_modelling/src/meanfield/models/meanfield_model_impl.h +++ b/neural_modelling/src/meanfield/models/meanfield_model_impl.h @@ -33,7 +33,6 @@ typedef struct meanfield_t { REAL b; REAL tauw; REAL Trefrac; - REAL Vthre; REAL Vreset; REAL delta_v; REAL ampnoise; diff --git a/spynnaker/pyNN/models/neuron/builds/meanfield_base.py b/spynnaker/pyNN/models/neuron/builds/meanfield_base.py index 7e1ccd1c6ea..84fcaa4348c 100644 --- a/spynnaker/pyNN/models/neuron/builds/meanfield_base.py +++ b/spynnaker/pyNN/models/neuron/builds/meanfield_base.py @@ -41,7 +41,6 @@ class MeanfieldBase(AbstractPyNNMeanfieldModelStandard): "TvN", "Vthre", "err_func", "isyn_exc", "isyn_inh"}) def __init__(self, - nbr=1., a=0., b=1., tauw=1., @@ -123,7 +122,7 @@ def __init__(self, sample=100, err_func=0.): # pylint: disable=too-many-arguments, too-many-locals - neuron_model = MeanfieldOfAdexNetwork(nbr, a, b, tauw, Trefrac, + neuron_model = MeanfieldOfAdexNetwork(a, b, tauw, Trefrac, Vreset, delta_v, ampnoise, Timescale_inv, Ve, Vi, w) params_from_network = ParamsFromNetwork(pconnec, q_exc, q_inh, diff --git a/spynnaker/pyNN/models/neuron/neuron_models/meanfield_of_adex_network.py b/spynnaker/pyNN/models/neuron/neuron_models/meanfield_of_adex_network.py index b4bac9dd57b..fae84f370df 100644 --- a/spynnaker/pyNN/models/neuron/neuron_models/meanfield_of_adex_network.py +++ b/spynnaker/pyNN/models/neuron/neuron_models/meanfield_of_adex_network.py @@ -55,7 +55,7 @@ class MeanfieldOfAdexNetwork(AbstractNeuronModel): """ Model of meanfield due to A.Destehexe et al """ __slots__ = [ - "_nbr", "_a", "_b", "_tauw", "_Trefrac", "_Vreset", "_delta_v", + "_a", "_b", "_tauw", "_Trefrac", "_Vreset", "_delta_v", "_ampnoise", "_Timescale_inv", "_Ve_init", "_Vi_init", "_w_init", ] @@ -70,8 +70,7 @@ def __init__(self, nbr, a, b, tauw, """ super().__init__( - [DataType.UINT32, #nbr - DataType.S1615, #a + [DataType.S1615, #a DataType.UINT32, #nbr DataType.S1615, #b DataType.S1615, #tauw DataType.S1615, #Trefrac @@ -84,7 +83,7 @@ def __init__(self, nbr, a, b, tauw, DataType.S1615, #W DataType.S1615], # this_h (= machine_time_step) [DataType.S1615]) # machine_time_step - self._nbr = nbr + #self._nbr = nbr self._a = a self._b = b self._tauw = tauw @@ -105,7 +104,7 @@ def get_n_cpu_cycles(self, n_neurons): @overrides(AbstractStandardNeuronComponent.add_parameters) def add_parameters(self, parameters): ###--neuron--### - parameters[NBR] = self._nbr + #parameters[NBR] = self._nbr parameters[A] = self._a parameters[B] = self._b parameters[TAUW] = self._tauw @@ -143,7 +142,8 @@ def get_values(self, parameters, state_variables, vertex_slice, ts): # Add the rest of the data return [ - parameters[NBR],parameters[A],parameters[B],parameters[TAUW], + #parameters[NBR], + parameters[A],parameters[B],parameters[TAUW], parameters[TREFRAC], parameters[VRESET],parameters[DELTA_V],parameters[AMPNOISE], parameters[TIMESCALE_INV], @@ -157,7 +157,8 @@ def get_values(self, parameters, state_variables, vertex_slice, ts): def update_values(self, values, parameters, state_variables): # Decode the values - (_nbr, _a, _b, _tauw, + (#_nbr, + _a, _b, _tauw, _Trefrac, _Vreset, _delta_v, _ampnoise, _Timescale_inv, Ve, Vi, w, _this_h) = values @@ -171,9 +172,9 @@ def update_values(self, values, parameters, state_variables): ###--Meanfield--### ################ - @property - def nbr(self): - return self._nbr + # @property + # def nbr(self): + # return self._nbr @property From 4b7f2195f4ab249b06481a494ee49d1aad8d009b Mon Sep 17 00:00:00 2001 From: Garandel Date: Wed, 3 Nov 2021 14:21:10 +0000 Subject: [PATCH 40/44] modified: ../../../src/meanfield/models/meanfield_model_impl.c modified: ../../../../spynnaker/pyNN/models/neuron/builds/meanfield_base.py modified: ../../../../spynnaker/pyNN/models/neuron/neuron_models/meanfield_of_adex_network.py No clue of why w return uint32 DataType and not S1615. Will try in switching Vi and w --- .../meanfield/models/meanfield_model_impl.c | 27 ++++++++++--------- .../models/neuron/builds/meanfield_base.py | 6 ++--- .../meanfield_of_adex_network.py | 15 +++++------ 3 files changed, 25 insertions(+), 23 deletions(-) diff --git a/neural_modelling/src/meanfield/models/meanfield_model_impl.c b/neural_modelling/src/meanfield/models/meanfield_model_impl.c index dc8629b7d16..69fd1e1ff68 100644 --- a/neural_modelling/src/meanfield/models/meanfield_model_impl.c +++ b/neural_modelling/src/meanfield/models/meanfield_model_impl.c @@ -311,7 +311,7 @@ void RK2_midpoint_MF(REAL h, meanfield_t *meanfield, REAL lastVe = meanfield->Ve; REAL lastVi = meanfield->Vi; REAL lastW = meanfield->w; - //REAL tauw = meanfield->tauw; + REAL tauw = meanfield->tauw; //REAL W_tauw; @@ -338,24 +338,27 @@ void RK2_midpoint_MF(REAL h, meanfield_t *meanfield, REAL k1_exc = (lastTF_exc - lastVe)*T_inv; - REAL k2_exc = lastVe + h*k1_exc; + REAL k2_exc = (lastTF_exc - (lastVe + h*k1_exc))*T_inv; - meanfield->Ve += lastVe + REAL_HALF(h*(k1_exc + k2_exc))*REAL_CONST(0.5); + meanfield->Ve += lastVe + REAL_HALF(h*(k1_exc + k2_exc)); //meanfield->Ve += lastVe + (REAL_HALF(lastTF_exc - lastVe) * (REAL_CONST(2.0)-h) * h); - meanfield->Ve = meanfield->Ve * T_inv; + //meanfield->Ve = meanfield->Ve * T_inv; + REAL k1_inh = (lastTF_inh - lastVi)*T_inv; + REAL k2_inh = lastVi - h*k1_inh;//(lastTF_inh - (lastVi + h*k1_inh))*T_inv; - meanfield->Vi += lastVi + (REAL_HALF(lastTF_inh - lastVi) * (REAL_CONST(2.0)-h) * h); - meanfield->Vi = meanfield->Vi * ONE; //*T_inv normaly + meanfield->Vi += lastVi + REAL_HALF(h*(k1_inh + k2_inh)); + //meanfield->Vi += lastVi + (REAL_HALF(lastTF_inh - lastVi) * (REAL_CONST(2.0)-h) * h); + //meanfield->Vi = meanfield->Vi * ONE; //*T_inv normaly - REAL k1_W = -lastW;//tauw; - REAL k2_W = -lastW*(ONE+h);//tauw; + REAL k1_W = -lastW/tauw + meanfield->b * lastVe; + REAL k2_W = lastW + h * k1_W;//-(lastW + h*k1_W)/tauw + meanfield->b * lastVe; - //W_tauw = -lastW ;//+ meanfield->b*lastVe*meanfield->tauw - // + meanfield->a*(pNetwork->muV-pNetwork->El)*meanfield->tauw; - meanfield->w += meanfield->tauw ; - //meanfield->w += lastW;///REAL_CONST(10.);//lastW + (h*(k1_W+k2_W)); + //W_tauw = -lastW + meanfield->b*lastVe*tauw + // + meanfield->a*(pNetwork->muV-pNetwork->El)*tauw; + //meanfield->w += meanfield->tauw ; + meanfield->w += lastW + REAL_HALF(h*(k1_W+k2_W)); } diff --git a/spynnaker/pyNN/models/neuron/builds/meanfield_base.py b/spynnaker/pyNN/models/neuron/builds/meanfield_base.py index 84fcaa4348c..99994fa840b 100644 --- a/spynnaker/pyNN/models/neuron/builds/meanfield_base.py +++ b/spynnaker/pyNN/models/neuron/builds/meanfield_base.py @@ -42,8 +42,8 @@ class MeanfieldBase(AbstractPyNNMeanfieldModelStandard): "err_func", "isyn_exc", "isyn_inh"}) def __init__(self, a=0., - b=1., - tauw=1., + b=0, + tauw=1.0, Trefrac=5.0, Vreset=-65., delta_v=-0.5, @@ -119,7 +119,7 @@ def __init__(self, isyn_exc=0.0, isyn_inh=0.0, - sample=100, + sample=1000, err_func=0.): # pylint: disable=too-many-arguments, too-many-locals neuron_model = MeanfieldOfAdexNetwork(a, b, tauw, Trefrac, diff --git a/spynnaker/pyNN/models/neuron/neuron_models/meanfield_of_adex_network.py b/spynnaker/pyNN/models/neuron/neuron_models/meanfield_of_adex_network.py index fae84f370df..42359d97383 100644 --- a/spynnaker/pyNN/models/neuron/neuron_models/meanfield_of_adex_network.py +++ b/spynnaker/pyNN/models/neuron/neuron_models/meanfield_of_adex_network.py @@ -21,7 +21,7 @@ AbstractStandardNeuronComponent) ###--Meanfield Params--### -NBR = "nbr" +#NBR = "nbr" A = "a" B = "b" TAUW = "tauw" @@ -36,7 +36,7 @@ UNITS = { ###--Meanfield--### - NBR: "", + #NBR: "", A: "nS", B: "nS", TAUW: "ms", @@ -47,7 +47,7 @@ TIMESCALE_INV: "Hz", VE: "Hz", VI: "Hz", - W: "mV ", + W: "pA", } @@ -59,7 +59,7 @@ class MeanfieldOfAdexNetwork(AbstractNeuronModel): "_ampnoise", "_Timescale_inv", "_Ve_init", "_Vi_init", "_w_init", ] - def __init__(self, nbr, a, b, tauw, + def __init__(self, a, b, tauw, Trefrac, Vreset, delta_v, ampnoise, Timescale_inv, Ve_init, Vi_init, w_init): @@ -142,7 +142,6 @@ def get_values(self, parameters, state_variables, vertex_slice, ts): # Add the rest of the data return [ - #parameters[NBR], parameters[A],parameters[B],parameters[TAUW], parameters[TREFRAC], parameters[VRESET],parameters[DELTA_V],parameters[AMPNOISE], @@ -157,8 +156,8 @@ def get_values(self, parameters, state_variables, vertex_slice, ts): def update_values(self, values, parameters, state_variables): # Decode the values - (#_nbr, - _a, _b, _tauw, + #(#_nbr, + (_a, _b, _tauw, _Trefrac, _Vreset, _delta_v, _ampnoise, _Timescale_inv, Ve, Vi, w, _this_h) = values @@ -227,7 +226,7 @@ def Vi_init(self): @property def w_init(self): - """ Settable model parameter: :math:`V_{i}` + """ Settable model parameter: :math:`w` :rtype: float """ From 3cdf4a96cd2345f3d677ec020b2d4b5c0177eed5 Mon Sep 17 00:00:00 2001 From: Garandel Date: Thu, 4 Nov 2021 12:42:43 +0000 Subject: [PATCH 41/44] modified: ../../../src/meanfield/implementations/meanfield_impl_standard.h modified: ../../../src/meanfield/models/meanfield_model.h modified: ../../../src/meanfield/models/meanfield_model_impl.c modified: ../../../../spynnaker/pyNN/models/neuron/neuron_models/meanfield_of_adex_network.py SAVE POINT now that's fonctionnaly work. NEED to optimise or doing real ode solver and error_function --- .../src/meanfield/implementations/meanfield_impl_standard.h | 2 +- neural_modelling/src/meanfield/models/meanfield_model.h | 2 +- neural_modelling/src/meanfield/models/meanfield_model_impl.c | 4 ++-- .../models/neuron/neuron_models/meanfield_of_adex_network.py | 3 +-- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/neural_modelling/src/meanfield/implementations/meanfield_impl_standard.h b/neural_modelling/src/meanfield/implementations/meanfield_impl_standard.h index 100b393c7e6..65507251d43 100644 --- a/neural_modelling/src/meanfield/implementations/meanfield_impl_standard.h +++ b/neural_modelling/src/meanfield/implementations/meanfield_impl_standard.h @@ -427,7 +427,7 @@ static void neuron_impl_do_timestep_update( exc_input_values, input_types, firing_rate_Ve); input_type_convert_inhibitory_input_to_current( inh_input_values, input_types, firing_rate_Vi); - + // input_t external_bias += additional_input_get_input_value_as_current( // additional_inputs, firing_rate); diff --git a/neural_modelling/src/meanfield/models/meanfield_model.h b/neural_modelling/src/meanfield/models/meanfield_model.h index 8669138e3a2..7b871ed5629 100644 --- a/neural_modelling/src/meanfield/models/meanfield_model.h +++ b/neural_modelling/src/meanfield/models/meanfield_model.h @@ -100,7 +100,7 @@ void neuron_model_has_spiked(meanfield_t *restrict meanfield); //! parameters specified in neuron state_t meanfield_model_get_firing_rate_Ve(const meanfield_t *meanfield); state_t meanfield_model_get_firing_rate_Vi(const meanfield_t *meanfield); -state_t meanfield_model_get_Fout_th(const ParamsFromNetwork_t *params_from_network); +state_t meanfield_model_get_adaptation_W(const meanfield_t *meanfield); //! \brief printout of state variables i.e. those values that might change //! \param[in] neuron: a pointer to a neuron parameter struct which contains all diff --git a/neural_modelling/src/meanfield/models/meanfield_model_impl.c b/neural_modelling/src/meanfield/models/meanfield_model_impl.c index 69fd1e1ff68..17ba154fa74 100644 --- a/neural_modelling/src/meanfield/models/meanfield_model_impl.c +++ b/neural_modelling/src/meanfield/models/meanfield_model_impl.c @@ -336,7 +336,7 @@ void RK2_midpoint_MF(REAL h, meanfield_t *meanfield, */ - + //cut more the equation for underflowed ITCM!! REAL k1_exc = (lastTF_exc - lastVe)*T_inv; REAL k2_exc = (lastTF_exc - (lastVe + h*k1_exc))*T_inv; @@ -358,7 +358,7 @@ void RK2_midpoint_MF(REAL h, meanfield_t *meanfield, //W_tauw = -lastW + meanfield->b*lastVe*tauw // + meanfield->a*(pNetwork->muV-pNetwork->El)*tauw; //meanfield->w += meanfield->tauw ; - meanfield->w += lastW + REAL_HALF(h*(k1_W+k2_W)); + meanfield->w += lastVi;//lastW ;//+ REAL_HALF(h*(k1_W+k2_W)); } diff --git a/spynnaker/pyNN/models/neuron/neuron_models/meanfield_of_adex_network.py b/spynnaker/pyNN/models/neuron/neuron_models/meanfield_of_adex_network.py index 42359d97383..c192b55e8b4 100644 --- a/spynnaker/pyNN/models/neuron/neuron_models/meanfield_of_adex_network.py +++ b/spynnaker/pyNN/models/neuron/neuron_models/meanfield_of_adex_network.py @@ -56,7 +56,7 @@ class MeanfieldOfAdexNetwork(AbstractNeuronModel): """ __slots__ = [ "_a", "_b", "_tauw", "_Trefrac", "_Vreset", "_delta_v", - "_ampnoise", "_Timescale_inv", "_Ve_init", "_Vi_init", "_w_init", + "_ampnoise", "_Timescale_inv", "_Ve_init", "_Vi_init", "_w_init" ] def __init__(self, a, b, tauw, @@ -83,7 +83,6 @@ def __init__(self, a, b, tauw, DataType.S1615, #W DataType.S1615], # this_h (= machine_time_step) [DataType.S1615]) # machine_time_step - #self._nbr = nbr self._a = a self._b = b self._tauw = tauw From 4728d48af95aaa7a1254f1b6631d0795466cba55 Mon Sep 17 00:00:00 2001 From: Garandel Date: Thu, 4 Nov 2021 17:57:40 +0000 Subject: [PATCH 42/44] modified: ../../../src/meanfield/models/mathsbox.h modified: ../../../src/meanfield/models/meanfield_model_impl.c modified error_function with midpoint methode for integration. will do pregressively trapezoidale and Simpson if possible in ITCM BUT try to have an homogeneous patern i.e. EULER and Midpoint integrale for error function. --- .../src/meanfield/models/mathsbox.h | 3 ++- .../meanfield/models/meanfield_model_impl.c | 25 +++++++++++-------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/neural_modelling/src/meanfield/models/mathsbox.h b/neural_modelling/src/meanfield/models/mathsbox.h index dc6abf625f9..b26741f5119 100644 --- a/neural_modelling/src/meanfield/models/mathsbox.h +++ b/neural_modelling/src/meanfield/models/mathsbox.h @@ -4,6 +4,7 @@ #include #include #include +#include "../../common/maths-util.h" //#include @@ -19,5 +20,5 @@ typedef struct mathsbox_t { //typedef struct mathsbox_params_t* mathsbox_pointer_t; -void error_function(REAL x, REAL factor, mathsbox_t *restrict mathsbox); +void error_function(REAL argument, mathsbox_t *restrict mathsbox); #endif \ No newline at end of file diff --git a/neural_modelling/src/meanfield/models/meanfield_model_impl.c b/neural_modelling/src/meanfield/models/meanfield_model_impl.c index 17ba154fa74..b3f1901be18 100644 --- a/neural_modelling/src/meanfield/models/meanfield_model_impl.c +++ b/neural_modelling/src/meanfield/models/meanfield_model_impl.c @@ -69,18 +69,23 @@ static inline void neuron_ode( ################################################################### */ -void error_function( REAL x, REAL argument, mathsbox_t *restrict mathsbox){ +void error_function(REAL argument, mathsbox_t *restrict mathsbox){ //devra coder fonction powerof - REAL dt = x/mathsbox->error_func_sample; + REAL step = argument/mathsbox->error_func_sample; + REAL x; REAL t; //REAL Pi = 3.1415927;// here was a k REAL two_over_sqrt_Pi = REAL_CONST(1.128379167); //APPROXIMATION - REAL Erfc = 0.;//mathsbox->err_func; - for(t=0; t<=x; t+=dt){ + REAL Erf = ZERO;//mathsbox->err_func; + REAL Erfc = ZERO; + + for(x=0; x<=argument; x+=step){ //Erfc += factor*(2/sqrtk(Pi))*expk(-(t*t)); // the real one overflowed ITCM - Erfc += argument*two_over_sqrt_Pi*expk(-(t*t)); //working like this one + t = x + REAL_HALF(step); + Erf += step*two_over_sqrt_Pi*expk(-(t*t)); //working like this one } + Erfc = ONE-Erf; mathsbox->err_func = Erfc; @@ -210,11 +215,10 @@ void get_fluct_regime_varsup(REAL Ve, REAL Vi, REAL W, ParamsFromNetwork_t *rest doit trouver une bonne fonction pour faire sqrt ... |->sqrtk() ne fonctionne pas !!! */ - pNetwork->sV = Fe*(Ue*Te)*(Ue*Te)/REAL_CONST(2.)/(Te+Tm)\ + Fi*(Ti*Ui)*(Ti*Ui)/REAL_CONST(2.)/(Ti+Tm); - + if (FeGl; @@ -273,7 +277,7 @@ void TF(REAL Ve, REAL Vi, REAL W, get_fluct_regime_varsup(Ve, Vi, W, pNetwork); threshold_func(pNetwork, Pfit); - limit = REAL_HALF(Gl/(pNetwork->TvN * Cm)); + /* normalement sqrt: argument = (pNetwork->Vthre - pNetwork->muV)/sqrtk(REAL_CONST(2.))/pNetwork->sV; @@ -282,9 +286,10 @@ void TF(REAL Ve, REAL Vi, REAL W, if (pNetwork->sVsV += ACS_DBL_TINY; } + //factor = REAL_HALF(Gl/(pNetwork->TvN * Cm)); argument = (pNetwork->Vthre - pNetwork->muV)/(REAL_CONST(1.4142137)*pNetwork->sV); - error_function(limit, argument, mathsbox); + error_function(argument, mathsbox); /* if (pNetwork->P0 == 0.){ mathsbox->err_func = 1; a simple test From cbcdb45949041f07b9a0ac35c7aeae7fd1f3f9d8 Mon Sep 17 00:00:00 2001 From: Garandel Date: Fri, 5 Nov 2021 13:45:31 +0000 Subject: [PATCH 43/44] modified: ../../../src/meanfield/models/meanfield_model_impl.c modified: ../../../../spynnaker/pyNN/models/neuron/builds/meanfield_base.py Did some cleanning, correction and rewriting of euler, RK2, mu_Ge and modif TvN= Tv only because of the original paper. Need to ask for that!! Modif T_inv in value. need to find a way to plot but plt.show don't work on the terminal. --- .../meanfield/models/meanfield_model_impl.c | 199 +++++++++--------- .../models/neuron/builds/meanfield_base.py | 5 +- 2 files changed, 98 insertions(+), 106 deletions(-) diff --git a/neural_modelling/src/meanfield/models/meanfield_model_impl.c b/neural_modelling/src/meanfield/models/meanfield_model_impl.c index b3f1901be18..0752b1415c0 100644 --- a/neural_modelling/src/meanfield/models/meanfield_model_impl.c +++ b/neural_modelling/src/meanfield/models/meanfield_model_impl.c @@ -70,8 +70,13 @@ static inline void neuron_ode( */ void error_function(REAL argument, mathsbox_t *restrict mathsbox){ -//devra coder fonction powerof - +/* + * Error function with integral computing by midpoint method + * Will do the Simpson if ITCM is ok + * + * Sampling of error function is maybe connected to the time_step need to investigate. + */ + mathsbox->err_func = 0.; REAL step = argument/mathsbox->error_func_sample; REAL x; REAL t; @@ -129,7 +134,7 @@ void threshold_func(ParamsFromNetwork_t *restrict pNetwork, pFitPolynomial_t *re REAL P1 = Pfit->P1; REAL P2 = Pfit->P2; REAL P3 = Pfit->P3; - REAL P4 = Pfit->P4; + //REAL P4 = Pfit->P4; REAL P5 = Pfit->P5; REAL P6 = Pfit->P6; REAL P7 = Pfit->P7; @@ -157,11 +162,10 @@ void threshold_func(ParamsFromNetwork_t *restrict pNetwork, pFitPolynomial_t *re void get_fluct_regime_varsup(REAL Ve, REAL Vi, REAL W, ParamsFromNetwork_t *restrict pNetwork) { - REAL Fe; - REAL Fi; - REAL muGe, muGi, muG; - REAL Ue, Ui; - REAL Tm, Tv; + //REAL Fe, Fi; + //REAL muGe, muGi, muG; + //REAL Ue, Ui; + //REAL Tm, Tv; REAL gei = pNetwork->gei; REAL pconnec = pNetwork->pconnec; @@ -185,28 +189,32 @@ void get_fluct_regime_varsup(REAL Ve, REAL Vi, REAL W, ParamsFromNetwork_t *rest // here TOTAL (sum over synapses) excitatory and inhibitory input - Fe = Ve * (REAL_CONST(1.)-gei)*pconnec*Ntot; // default is 1 !! - Fi = Vi * gei*pconnec*Ntot; + REAL Fe = Ve * (REAL_CONST(1.)-gei)*pconnec*Ntot; // default is 1 !! + REAL Fi = Vi * gei*pconnec*Ntot; - muGe = Qe*Te*Ve; // normaly = Ve*Te*Qe*Ke with Ke = p*Nue what it is? - muGi = Qi*Ti*Vi; + /* normaly = Ve*Te*Qe*Ke with Ke = p*N_exc what it is? + -> here N_exc = (1-gei)*Ntot*pconnec + So give the same + */ + REAL muGe = Qe*Te*Fe; //=Ve*Qe*Te*Ke + REAL muGi = Qi*Ti*Fi; - muG = Gl+muGe+muGi; + REAL muG = Gl + muGe + muGi; if (muG < ACS_DBL_TINY){ muG += ACS_DBL_TINY; } - pNetwork->muV = (muGe*Ee + muGi*Ei + Gl*El - W)/muG; + pNetwork->muV = (muGe*Ee + muGi*Ei + Gl*El - W)/muG; //Thomas : maybe will add explicitely a and b? pNetwork->muGn = muG/Gl; - Tm = Cm/muG; - - Ue = Qe/muG*(Ee-pNetwork->muV); - Ui = Qi/muG*(Ei-pNetwork->muV); + REAL Tm = Cm/muG; + REAL Ue = Qe*(Ee-pNetwork->muV)/muG; + REAL Ui = Qi*(Ei-pNetwork->muV)/muG; + /* normalement sqrt((Fe*(Ue*params->Te)*(Ue*params->Te)/2./(params->Te+Tm)+\ @@ -230,21 +238,22 @@ void get_fluct_regime_varsup(REAL Ve, REAL Vi, REAL W, ParamsFromNetwork_t *rest Fi += ACS_DBL_TINY; } - Tv = ( Fe*(Ue*Te)*(Ue*Te) + Fi*(Ti*Ui)*(Ti*Ui))\ + REAL Tv = ( Fe*(Ue*Te)*(Ue*Te) + Fi*(Ti*Ui)*(Ti*Ui))\ /(Fe*(Ue*Te)*(Ue*Te)/(Te+Tm) + Fi*(Ti*Ui)*(Ti*Ui)/(Ti+Tm)); if (Tv < ACS_DBL_TINY){ Tv += ACS_DBL_TINY; - } - - pNetwork->TvN = Tv*Gl/Cm; + } + /* + pNetwork->TvN = Tv*Gl/Cm; // Thomas : Heu, useless no?? + */ + pNetwork->TvN = Tv; } void TF(REAL Ve, REAL Vi, REAL W, - meanfield_t *meanfield, ParamsFromNetwork_t *restrict pNetwork, pFitPolynomial_t *restrict Pfit, mathsbox_t *restrict mathsbox){ @@ -254,13 +263,8 @@ void TF(REAL Ve, REAL Vi, REAL W, parameters are put in local in order to make the code clear. */ - - - REAL factor; - REAL argument; - REAL Gl = pNetwork->Gl; - REAL Cm = pNetwork->Cm; + if (pNetwork->Fout_th != ZERO){ @@ -287,17 +291,19 @@ void TF(REAL Ve, REAL Vi, REAL W, pNetwork->sV += ACS_DBL_TINY; } //factor = REAL_HALF(Gl/(pNetwork->TvN * Cm)); - argument = (pNetwork->Vthre - pNetwork->muV)/(REAL_CONST(1.4142137)*pNetwork->sV); + REAL argument = (pNetwork->Vthre - pNetwork->muV)/(REAL_CONST(1.4142137)*pNetwork->sV); error_function(argument, mathsbox); + /* - if (pNetwork->P0 == 0.){ - mathsbox->err_func = 1; a simple test - } - */ + REAL Gl = pNetwork->Gl; + REAL Cm = pNetwork->Cm; + pNetwork->Fout_th = (HALF*Gl) * mathsbox->err_func / (Cm*pNetwork->TvN);// In fact = 1/(2.*Tv) * err_func , that's it'!!! + If remove that's will do less instruction - pNetwork->Fout_th = (HALF*Gl) * mathsbox->err_func / (Cm*pNetwork->TvN);// REAL ONE - //pNetwork->Fout_th = mathsbox->err_func ; //TEST + Put TvN<-:Tv because Tv not in pNetwork + */ + pNetwork->Fout_th = (HALF*pNetwork->TvN) * mathsbox->err_func ; if (pNetwork->Fout_th < ACS_DBL_TINY){ @@ -312,98 +318,83 @@ void RK2_midpoint_MF(REAL h, meanfield_t *meanfield, pFitPolynomial_t *restrict Pfit_exc, pFitPolynomial_t *restrict Pfit_inh, mathsbox_t *restrict mathsbox) { + + /* Propose for now a=0 + * + */ REAL lastVe = meanfield->Ve; REAL lastVi = meanfield->Vi; REAL lastW = meanfield->w; - REAL tauw = meanfield->tauw; - //REAL W_tauw; - + REAL tauw = meanfield->tauw; REAL T_inv = meanfield->Timescale_inv; + REAL b = meanfield->b; + + /* + if (h=0.){ + lastW = meanfield->Ve*tauw*b; + } + else{ + lastW = meanfield->w; + } + */ + - TF(lastVe, lastVi, lastW, meanfield, pNetwork, Pfit_exc, mathsbox); + TF(lastVe, lastVi, lastW, pNetwork, Pfit_exc, mathsbox); REAL lastTF_exc = pNetwork->Fout_th; - TF(lastVe, lastVi, lastW, meanfield, pNetwork, Pfit_inh, mathsbox); + TF(lastVe, lastVi, lastW, pNetwork, Pfit_inh, mathsbox); REAL lastTF_inh = pNetwork->Fout_th; - //configVe stand for TF1 i.e TF for exitatory pop. SO configVi is for TF2 - //In fact no configVe and configVi just config, all in the same file. +/* + * EULER Explicite method + * It's very instable if for now h<0.2 for 20ms + * + * NEED to give also the error of the method here : + * 0.5*h^2*u''(t_n) + o(h^2) + */ + /* - some troubles maybe come from constants : - from spynnaker.pyNN.utilities.constants - - and - - pyNN/models/recorder.py - - */ - - //cut more the equation for underflowed ITCM!! + REAL k1_exc = (lastTF_exc - lastVe)*T_inv; - REAL k2_exc = (lastTF_exc - (lastVe + h*k1_exc))*T_inv; + meanfield->Ve += h * k1_exc ; - meanfield->Ve += lastVe + REAL_HALF(h*(k1_exc + k2_exc)); + REAL k1_inh = (lastTF_inh - lastVi)*T_inv; + meanfield->Vi += h * k1_inh ; - //meanfield->Ve += lastVe + (REAL_HALF(lastTF_exc - lastVe) * (REAL_CONST(2.0)-h) * h); - //meanfield->Ve = meanfield->Ve * T_inv; + REAL k1_W = -lastW/tauw + meanfield->b * lastVe; + meanfield->w += h * k1_W; - REAL k1_inh = (lastTF_inh - lastVi)*T_inv; - REAL k2_inh = lastVi - h*k1_inh;//(lastTF_inh - (lastVi + h*k1_inh))*T_inv; + */ - meanfield->Vi += lastVi + REAL_HALF(h*(k1_inh + k2_inh)); - //meanfield->Vi += lastVi + (REAL_HALF(lastTF_inh - lastVi) * (REAL_CONST(2.0)-h) * h); - //meanfield->Vi = meanfield->Vi * ONE; //*T_inv normaly +/* + * RUNGE-KUTTA 2nd order Midpoint + */ - REAL k1_W = -lastW/tauw + meanfield->b * lastVe; - REAL k2_W = lastW + h * k1_W;//-(lastW + h*k1_W)/tauw + meanfield->b * lastVe; - //W_tauw = -lastW + meanfield->b*lastVe*tauw - // + meanfield->a*(pNetwork->muV-pNetwork->El)*tauw; - //meanfield->w += meanfield->tauw ; - meanfield->w += lastVi;//lastW ;//+ REAL_HALF(h*(k1_W+k2_W)); + //cut more the equation for underflowed ITCM!! + REAL k1_exc = (lastTF_exc - lastVe)*T_inv; + REAL alpha_exc = lastVe + h*k1_exc; + REAL k2_exc = (lastTF_exc - alpha_exc )*T_inv; + + meanfield->Ve += REAL_HALF(h*(k1_exc + k2_exc)); -} - + REAL k1_inh = (lastTF_inh - lastVi)*T_inv; + REAL alpha_inh = lastVi + h*k1_inh; + REAL k2_inh = (lastTF_inh - alpha_inh)*T_inv; + + meanfield->Vi += REAL_HALF(h*(k1_inh + k2_inh)); + + REAL k1_W = -lastW/tauw + b * lastVe; + REAL alpha_w = lastW + h*k1_W; + REAL k2_W = -alpha_w/tauw + b * lastVe; + + meanfield->w += REAL_HALF(h*(k1_W+k2_W)); -/*############################################################################## -end of reuse -################################################################################# -*/ -/*! - * \brief Midpoint is best balance between speed and accuracy so far. - * \details From ODE solver comparison work, paper shows that Trapezoid version - * gives better accuracy at small speed cost - * \param[in] h: threshold - * \param[in,out] neuron: The model being updated - * \param[in] input_this_timestep: the input - */ -/*static inline void rk2_kernel_midpoint( - REAL h, neuron_t *neuron, REAL input_this_timestep) { - // to match Mathematica names - REAL lastV1 = neuron->V; - REAL lastU1 = neuron->U; - REAL a = neuron->A; - REAL b = neuron->B; - - REAL pre_alph = REAL_CONST(140.0) + input_this_timestep - lastU1; - REAL alpha = pre_alph - + (REAL_CONST(5.0) + MAGIC_MULTIPLIER * lastV1) * lastV1; - REAL eta = lastV1 + REAL_HALF(h * alpha); - - // could be represented as a long fract? - REAL beta = REAL_HALF(h * (b * lastV1 - lastU1) * a); - - neuron->V += h * (pre_alph - beta - + (REAL_CONST(5.0) + MAGIC_MULTIPLIER * eta) * eta); - - neuron->U += a * h * (-lastU1 - beta + b * eta); } -*/ - void meanfield_model_set_global_neuron_params( const global_neuron_params_t *params) { diff --git a/spynnaker/pyNN/models/neuron/builds/meanfield_base.py b/spynnaker/pyNN/models/neuron/builds/meanfield_base.py index 99994fa840b..23658d56b07 100644 --- a/spynnaker/pyNN/models/neuron/builds/meanfield_base.py +++ b/spynnaker/pyNN/models/neuron/builds/meanfield_base.py @@ -42,13 +42,13 @@ class MeanfieldBase(AbstractPyNNMeanfieldModelStandard): "err_func", "isyn_exc", "isyn_inh"}) def __init__(self, a=0., - b=0, + b=0., tauw=1.0, Trefrac=5.0, Vreset=-65., delta_v=-0.5, ampnoise=0.0, - Timescale_inv=0.5, + Timescale_inv=200, Ve=9., Vi=23., w=0.25, @@ -122,6 +122,7 @@ def __init__(self, sample=1000, err_func=0.): # pylint: disable=too-many-arguments, too-many-locals + w = Ve * b * tauw + a * (El-muV0) neuron_model = MeanfieldOfAdexNetwork(a, b, tauw, Trefrac, Vreset, delta_v, ampnoise, Timescale_inv, Ve, Vi, w) From 9650299350b8734859c9d8e572be7da2fd65a39e Mon Sep 17 00:00:00 2001 From: Garandel Date: Fri, 19 Nov 2021 15:02:21 +0000 Subject: [PATCH 44/44] modified: ../../../src/meanfield/models/mathsbox.h modified: ../../../src/meanfield/models/meanfield_model_impl.c modified: ../../../../spynnaker/pyNN/models/neuron/builds/meanfield_base.py Do some clarification and try some method to remove the 'overflowed ITCM' message because of sqrtk sqrt function is not activated, so sV is on the square value. Need to find a solution for sqrt without overflowed ITCM --- .../src/meanfield/models/mathsbox.h | 6 +- .../meanfield/models/meanfield_model_impl.c | 148 ++++++++---------- .../models/neuron/builds/meanfield_base.py | 7 +- 3 files changed, 76 insertions(+), 85 deletions(-) diff --git a/neural_modelling/src/meanfield/models/mathsbox.h b/neural_modelling/src/meanfield/models/mathsbox.h index b26741f5119..62fa90ea0f9 100644 --- a/neural_modelling/src/meanfield/models/mathsbox.h +++ b/neural_modelling/src/meanfield/models/mathsbox.h @@ -1,10 +1,10 @@ #ifndef _MATHSBOX_H_ #define _MATHSBOX_H_ -#include +//#include #include #include -#include "../../common/maths-util.h" +//#include "../../common/maths-util.h" //#include @@ -16,6 +16,8 @@ typedef struct mathsbox_t { REAL error_func_sample; REAL err_func; + + REAL var_sqrt; }mathsbox_t; //typedef struct mathsbox_params_t* mathsbox_pointer_t; diff --git a/neural_modelling/src/meanfield/models/meanfield_model_impl.c b/neural_modelling/src/meanfield/models/meanfield_model_impl.c index 0752b1415c0..47d372936a8 100644 --- a/neural_modelling/src/meanfield/models/meanfield_model_impl.c +++ b/neural_modelling/src/meanfield/models/meanfield_model_impl.c @@ -33,29 +33,7 @@ static const global_neuron_params_t *global_params; * use cases 1.85 gives slightly better spike timings. */ //static const REAL SIMPLE_TQ_OFFSET = REAL_CONST(1.85); -/* -///////////////////////////////////////////////////////////// -#if 0 -// definition for Izhikevich neuron -static inline void neuron_ode( - REAL t, REAL stateVar[], REAL dstateVar_dt[], - neuron_t *neuron, REAL input_this_timestep) { - REAL V_now = stateVar[1]; - REAL U_now = stateVar[2]; - log_debug(" sv1 %9.4k V %9.4k --- sv2 %9.4k U %9.4k\n", stateVar[1], - neuron->V, stateVar[2], neuron->U); - - // Update V - dstateVar_dt[1] = - REAL_CONST(140.0) - + (REAL_CONST(5.0) + REAL_CONST(0.0400) * V_now) * V_now - U_now - + input_this_timestep; - - // Update U - dstateVar_dt[2] = neuron->A * (neuron->B * V_now - U_now); -} -#endif -*/ + //! \brief The original model uses 0.04, but this (1 ULP larger?) gives better //! numeric stability. @@ -63,32 +41,33 @@ static inline void neuron_ode( //! Thanks to Mantas Mikaitis for this! //static const REAL MAGIC_MULTIPLIER = REAL_CONST(0.040008544921875); - -/* #################################################################### - reuse of izk for meanfields - ################################################################### - */ - void error_function(REAL argument, mathsbox_t *restrict mathsbox){ -/* - * Error function with integral computing by midpoint method +/**************************************************************************** + * Error function with integral computing by midpoint method OK * Will do the Simpson if ITCM is ok * - * Sampling of error function is maybe connected to the time_step need to investigate. - */ + * Sampling of error function is maybe connected to the time_step need to + * investigate. + * + * expk take : ~ 570 bytes + sqrtk take : ~1250 bytes + *****************************************************************************/ mathsbox->err_func = 0.; REAL step = argument/mathsbox->error_func_sample; REAL x; REAL t; - //REAL Pi = 3.1415927;// here was a k + REAL Pi = REAL_CONST(3.1415927);// here was a k REAL two_over_sqrt_Pi = REAL_CONST(1.128379167); //APPROXIMATION - REAL Erf = ZERO;//mathsbox->err_func; + REAL Erf = ZERO; REAL Erfc = ZERO; for(x=0; x<=argument; x+=step){ - //Erfc += factor*(2/sqrtk(Pi))*expk(-(t*t)); // the real one overflowed ITCM + + //Erfc += factor*(2/sqrtk(Pi))*expk(-(t*t)); // the real one overflowed ITCM because of expk and sqrtk t = x + REAL_HALF(step); Erf += step*two_over_sqrt_Pi*expk(-(t*t)); //working like this one + //Erf += step*two_over_sqrt_Pi*(-(t*t));//TEST + //Erf += step*(REAL_CONST(2.)/sqrtk(Pi))*expk(-(t*t)); // TEST sqrtk ONE } Erfc = ONE-Erf; @@ -96,6 +75,37 @@ void error_function(REAL argument, mathsbox_t *restrict mathsbox){ } +/* +double square_root_of(REAL number) +{ + /*! square root method take from Quake III Arena + * source code, attribute to John Carmack. + * Under GNU GPL licence. + * + * Implement here just to see if something was lighter than sqrt.c + * + */ +/* + REAL x, y, f; + REAL i; + f = REAL_CONST(1.5); + + x = REAL_HALF(number); + y = number; + + i = *(REAL *) &y; + i = 0x5f3759df - (i >> 1); + y = *(REAL *) &i; + y = y * (f - (x * y * y)); + y = y * (f - (x * y * y)); + + return number*y; + +} +*/ + + + void threshold_func(ParamsFromNetwork_t *restrict pNetwork, pFitPolynomial_t *restrict Pfit) { @@ -161,11 +171,7 @@ void threshold_func(ParamsFromNetwork_t *restrict pNetwork, pFitPolynomial_t *re void get_fluct_regime_varsup(REAL Ve, REAL Vi, REAL W, ParamsFromNetwork_t *restrict pNetwork) { - - //REAL Fe, Fi; - //REAL muGe, muGi, muG; - //REAL Ue, Ui; - //REAL Tm, Tv; + // Need some comments REAL gei = pNetwork->gei; REAL pconnec = pNetwork->pconnec; @@ -180,15 +186,7 @@ void get_fluct_regime_varsup(REAL Ve, REAL Vi, REAL W, ParamsFromNetwork_t *rest REAL Ee = pNetwork->Ee; REAL Cm = pNetwork->Cm; - - - //REAL muV = pNetwork->muV; - //REAL muGn = pNetwork->muGn; - //REAL sV = pNetwork->sV; - //REAL TvN = pNetwork->TvN; - - // here TOTAL (sum over synapses) excitatory and inhibitory input - + REAL Fe = Ve * (REAL_CONST(1.)-gei)*pconnec*Ntot; // default is 1 !! REAL Fi = Vi * gei*pconnec*Ntot; @@ -217,15 +215,16 @@ void get_fluct_regime_varsup(REAL Ve, REAL Vi, REAL W, ParamsFromNetwork_t *rest /* - normalement sqrt((Fe*(Ue*params->Te)*(Ue*params->Te)/2./(params->Te+Tm)+\ - Fi*(params->Ti*Ui)*(params->Ti*Ui)/2./(params->Ti+Tm))) + normaly sqrt(REAL_HALF(Fe*(Ue*Te)*(Ue*Te)/(Te+Tm) + Fi*(Ti*Ui)*(Ti*Ui)/(Ti+Tm))) - doit trouver une bonne fonction pour faire sqrt ... - |->sqrtk() ne fonctionne pas !!! + need find a good sqrt function ... + |->sqrtk() takes too much ITCM !!! */ - pNetwork->sV = Fe*(Ue*Te)*(Ue*Te)/REAL_CONST(2.)/(Te+Tm)\ - + Fi*(Ti*Ui)*(Ti*Ui)/REAL_CONST(2.)/(Ti+Tm); + + REAL sV_sqr = REAL_HALF(Fe*(Ue*Te)*(Ue*Te)/(Te+Tm) + Fi*(Ti*Ui)*(Ti*Ui)/(Ti+Tm));//ITCM with err_func also, 1272 bytes over + + pNetwork->sV = sV_sqr; // square_root_of(sV_sqr); @@ -244,10 +243,9 @@ void get_fluct_regime_varsup(REAL Ve, REAL Vi, REAL W, ParamsFromNetwork_t *rest if (Tv < ACS_DBL_TINY){ Tv += ACS_DBL_TINY; } - /* - pNetwork->TvN = Tv*Gl/Cm; // Thomas : Heu, useless no?? - */ - pNetwork->TvN = Tv; + + pNetwork->TvN = Tv*Gl/Cm; // Thomas : Heu, useless no?? |resp-> TvN is a dimensional so usefull var + } @@ -265,8 +263,6 @@ void TF(REAL Ve, REAL Vi, REAL W, */ - - if (pNetwork->Fout_th != ZERO){ pNetwork->Fout_th = ACS_DBL_TINY; } @@ -292,18 +288,21 @@ void TF(REAL Ve, REAL Vi, REAL W, } //factor = REAL_HALF(Gl/(pNetwork->TvN * Cm)); REAL argument = (pNetwork->Vthre - pNetwork->muV)/(REAL_CONST(1.4142137)*pNetwork->sV); + error_function(argument, mathsbox); - /* + REAL Gl = pNetwork->Gl; REAL Cm = pNetwork->Cm; + /* pNetwork->Fout_th = (HALF*Gl) * mathsbox->err_func / (Cm*pNetwork->TvN);// In fact = 1/(2.*Tv) * err_func , that's it'!!! If remove that's will do less instruction Put TvN<-:Tv because Tv not in pNetwork + REMOVE this correction bcs TvN adimensional so usefull */ - pNetwork->Fout_th = (HALF*pNetwork->TvN) * mathsbox->err_func ; + pNetwork->Fout_th = (HALF*Gl) * mathsbox->err_func / (Cm*pNetwork->TvN); if (pNetwork->Fout_th < ACS_DBL_TINY){ @@ -330,15 +329,6 @@ void RK2_midpoint_MF(REAL h, meanfield_t *meanfield, REAL tauw = meanfield->tauw; REAL T_inv = meanfield->Timescale_inv; REAL b = meanfield->b; - - /* - if (h=0.){ - lastW = meanfield->Ve*tauw*b; - } - else{ - lastW = meanfield->w; - } - */ TF(lastVe, lastVi, lastW, pNetwork, Pfit_exc, mathsbox); @@ -348,13 +338,13 @@ void RK2_midpoint_MF(REAL h, meanfield_t *meanfield, TF(lastVe, lastVi, lastW, pNetwork, Pfit_inh, mathsbox); REAL lastTF_inh = pNetwork->Fout_th; -/* +/****************************************************** * EULER Explicite method * It's very instable if for now h<0.2 for 20ms * * NEED to give also the error of the method here : * 0.5*h^2*u''(t_n) + o(h^2) - */ + *******************************************************/ /* @@ -369,12 +359,10 @@ void RK2_midpoint_MF(REAL h, meanfield_t *meanfield, */ -/* - * RUNGE-KUTTA 2nd order Midpoint - */ - +/*********************************** + * RUNGE-KUTTA 2nd order Midpoint * + ***********************************/ - //cut more the equation for underflowed ITCM!! REAL k1_exc = (lastTF_exc - lastVe)*T_inv; REAL alpha_exc = lastVe + h*k1_exc; REAL k2_exc = (lastTF_exc - alpha_exc )*T_inv; diff --git a/spynnaker/pyNN/models/neuron/builds/meanfield_base.py b/spynnaker/pyNN/models/neuron/builds/meanfield_base.py index 23658d56b07..c5e69113336 100644 --- a/spynnaker/pyNN/models/neuron/builds/meanfield_base.py +++ b/spynnaker/pyNN/models/neuron/builds/meanfield_base.py @@ -41,8 +41,8 @@ class MeanfieldBase(AbstractPyNNMeanfieldModelStandard): "TvN", "Vthre", "err_func", "isyn_exc", "isyn_inh"}) def __init__(self, - a=0., - b=0., + a=4., + b=20., tauw=1.0, Trefrac=5.0, Vreset=-65., @@ -122,7 +122,8 @@ def __init__(self, sample=1000, err_func=0.): # pylint: disable=too-many-arguments, too-many-locals - w = Ve * b * tauw + a * (El-muV0) + #muVV = ((muGe*Erev_exc + muGi*Erev_inh + Gl*El - Ve*tauw*(b) + a*El) /muG)/ (1+a/muG) + #w = Ve * b * tauw + a * (El-muV0) neuron_model = MeanfieldOfAdexNetwork(a, b, tauw, Trefrac, Vreset, delta_v, ampnoise, Timescale_inv, Ve, Vi, w)