From dfa61d413e3c8608875af40c99cbb4a8f6cc6799 Mon Sep 17 00:00:00 2001 From: Jochen Martin Eppler Date: Fri, 13 Jun 2014 20:00:00 +0200 Subject: [PATCH] v2.4.0 --- Makefile.am | 12 +- acinclude.m4 | 146 ++- bootstrap.sh | 16 +- configure.ac.in | 216 +++-- conngen/Makefile.am | 2 +- conngen/cg_connect.cpp | 208 ++++- conngen/conngenmodule.cpp | 249 ++++- conngen/conngenmodule.h | 60 +- conngen/sli/conngen-interface.sli | 59 +- ...yright_header.txt => copyright_header.cpp} | 2 +- doc/copyright_header.py | 20 + doc/fulldoc.conf | 3 +- doc/normaldoc.conf | 3 +- doc/quickref.html | 78 +- examples/MyModule/Makefile.am | 2 +- examples/MyModule/drop_odd_spike_connection.h | 6 +- examples/MyModule/mymodule.cpp | 15 +- examples/MyModule/pif_psc_alpha.h | 5 +- .../sli/{mymodule.sli => mymodule-init.sli} | 6 +- examples/nest/ArtificialSynchrony.sli | 4 +- examples/nest/Brette_et_al_2007/benchmark.sli | 38 +- examples/nest/Brette_et_al_2007/coba.sli | 38 +- examples/nest/Brette_et_al_2007/cuba.sli | 38 +- examples/nest/Brette_et_al_2007/cuba_ps.sli | 38 +- examples/nest/Brette_et_al_2007/cuba_stdp.sli | 44 +- examples/nest/Brette_et_al_2007/hh_coba.sli | 38 +- examples/nest/BrodyHopfield.sli | 4 +- examples/nest/Makefile.am | 28 +- examples/nest/Potjans_2014/README.txt | 131 +++ examples/nest/Potjans_2014/microcircuit.sli | 615 +++++++++++++ examples/nest/Potjans_2014/network_params.sli | 162 ++++ examples/nest/Potjans_2014/plot_rates.py | 109 +++ .../nest/Potjans_2014/run_microcircuit.sh | 73 ++ examples/nest/Potjans_2014/sim_params.sli | 108 +++ .../nest/Potjans_2014/spike_analysis_www.py | 197 ++++ examples/nest/Potjans_2014/user_params.sli | 33 + examples/nest/balancedneuron-2.sli | 4 +- examples/nest/brunel-2000.sli | 84 +- examples/nest/brunel-2000_newconnect.sli | 345 +++++++ .../nest/brunel-2000_threaded_connect.sli | 44 +- examples/nest/brunel-sli_connect.sli | 39 +- examples/nest/brunel-sli_neuron.sli | 20 +- examples/nest/music/conttest.py | 9 +- .../nest/music/minimalmusicsetup-pynest.music | 11 + .../music/minimalmusicsetup_receivenest.py | 45 + .../music/minimalmusicsetup_receivenest.sli | 3 + .../nest/music/minimalmusicsetup_sendnest.py | 50 + .../nest/music/minimalmusicsetup_sendnest.sli | 3 + examples/nest/music/msgtest.py | 9 +- examples/nest/music/spike_exporter.sli | 15 +- .../three_neurons_threaded_receivenest.sli | 3 + .../music/three_neurons_threaded_sendnest.sli | 3 + examples/nest/plot_tsodyks_depr_fac.py | 2 +- .../nest/plot_tsodyks_shortterm_bursts.py | 3 +- examples/nest/tsodyks2_shortterm_bursts.sli | 44 +- examples/nest/tsodyks_depressing.sli | 2 +- examples/nest/tsodyks_facilitating.sli | 6 +- examples/nest/tsodyks_shortterm_bursts.sli | 46 +- .../neuronview}/neuronview.glade | 0 .../neuronview}/neuronview.py | 27 +- extras/ConnPlotter/ConnPlotter.py | 63 +- extras/ConnPlotter/LICENSE.ConnPlotter | 339 ------- extras/ConnPlotter/MANIFEST | 1 - extras/ConnPlotter/Makefile.am | 43 +- extras/ConnPlotter/__init__.py | 27 +- extras/ConnPlotter/colormaps.py | 28 +- extras/ConnPlotter/examples/__init__.py | 24 +- extras/ConnPlotter/examples/complex.py | 16 +- .../examples/connplotter_tutorial.py | 37 +- extras/ConnPlotter/examples/non_dale.py | 16 +- extras/ConnPlotter/examples/simple.py | 16 +- extras/ConnPlotter/setup.py | 18 +- extras/ConnPlotter/tcd_nest.py | 20 +- extras/automake-pre-1.14-fix.patch | 11 + extras/emacs/postscript-sli.el | 1 - lib/Makefile.am | 3 +- lib/sli/{arr.sli => arraylib.sli} | 87 +- lib/sli/filesystem.sli | 4 - lib/sli/helpinit.sli | 25 +- lib/sli/librandom.sli | 227 +---- lib/sli/library.sli | 813 +---------------- lib/sli/mathematica.sli | 300 +++--- lib/sli/nest-init.sli | 462 ++++++---- lib/sli/oosupport.sli | 24 +- lib/sli/processes.sli | 12 - lib/sli/ps-lib.sli | 25 +- lib/sli/regexp.sli | 4 - lib/sli/sli-init.sli | 195 ++-- lib/sli/typeinit.sli | 127 ++- lib/sli/unittest.sli | 28 +- lib/sli/version.sli | 496 ---------- libnestutil/Makefile.am | 1 - libnestutil/allocator.h | 1 + libnestutil/connection_generator.cpp | 73 -- libnestutil/connection_generator.h | 105 --- libnestutil/lockptr.h | 49 +- librandom/Makefile.am | 5 +- librandom/binomial_randomdev.cpp | 33 +- librandom/binomial_randomdev.h | 26 +- librandom/clipped_randomdev.h | 573 ++++++++++++ librandom/exp_randomdev.cpp | 19 + librandom/exp_randomdev.h | 25 +- librandom/gamma_randomdev.cpp | 29 +- librandom/gamma_randomdev.h | 34 +- librandom/gsl_binomial_randomdev.cpp | 67 +- librandom/gsl_binomial_randomdev.h | 41 +- librandom/gslrandomgen.cpp | 6 +- librandom/gslrandomgen.h | 36 +- librandom/knuthlfg.cpp | 22 + librandom/knuthlfg.h | 22 + librandom/librandom_exceptions.h | 87 ++ librandom/lognormal_randomdev.cpp | 86 ++ librandom/lognormal_randomdev.h | 104 +++ librandom/normal_randomdev.cpp | 39 +- librandom/normal_randomdev.h | 21 +- librandom/poisson_randomdev.cpp | 65 +- librandom/poisson_randomdev.h | 24 +- librandom/random_datums.h | 8 +- librandom/random_numbers.cpp | 194 ++-- librandom/random_numbers.h | 50 +- librandom/randomdev.cpp | 11 +- librandom/randomdev.h | 38 +- librandom/randomgen.h | 2 +- librandom/randomtest.cpp | 2 +- librandom/uniform_randomdev.cpp | 66 ++ librandom/uniform_randomdev.h | 120 +++ librandom/uniformint_randomdev.cpp | 31 +- librandom/uniformint_randomdev.h | 34 +- models/Makefile.am | 83 +- models/ac_generator.h | 2 - models/aeif_cond_alpha.h | 6 +- models/aeif_cond_alpha_RK5.cpp | 512 +++++++++++ models/aeif_cond_alpha_RK5.h | 419 +++++++++ models/aeif_cond_alpha_multisynapse.cpp | 680 ++++++++++++++ models/aeif_cond_alpha_multisynapse.h | 428 +++++++++ models/binary_neuron.h | 10 +- models/binary_neuron_impl.h | 11 +- models/cont_delay_connection.cpp | 23 +- models/correlomatrix_detector.cpp | 342 +++++++ models/correlomatrix_detector.h | 295 ++++++ models/dc_generator.h | 1 - models/gamma_sup_generator.cpp | 18 +- models/gamma_sup_generator.h | 2 - models/ginzburg_neuron.h | 2 + models/hh_cond_exp_traub.h | 2 - models/hh_psc_alpha.h | 2 - models/ht_neuron.h | 6 +- models/iaf_chs_2007.cpp | 261 ++++++ models/iaf_chs_2007.h | 332 +++++++ models/iaf_chxk_2008.cpp | 412 +++++++++ models/iaf_chxk_2008.h | 387 ++++++++ models/iaf_cond_alpha.h | 4 +- models/iaf_cond_exp.h | 4 +- models/iaf_cond_exp_sfa_rr.h | 2 +- models/iaf_neuron.h | 3 - models/iaf_psc_alpha.cpp | 6 +- models/iaf_psc_alpha.h | 3 + models/iaf_psc_alpha_multisynapse.cpp | 92 +- models/iaf_psc_alpha_multisynapse.h | 5 +- models/iaf_psc_delta.cpp | 2 +- models/iaf_psc_delta.h | 2 - models/iaf_psc_exp.cpp | 12 +- models/iaf_psc_exp.h | 10 +- models/iaf_psc_exp_multisynapse.cpp | 91 +- models/iaf_psc_exp_multisynapse.h | 6 +- models/iaf_tum_2000.h | 2 - models/izhikevich.cpp | 1 + models/izhikevich.h | 2 + models/mat2_psc_exp.h | 2 - models/mcculloch_pitts_neuron.h | 2 + models/mip_generator.cpp | 2 +- models/modelsmodule.cpp | 19 +- models/modelsmodule.h | 14 - models/music_event_out_proxy.cpp | 11 +- models/noise_generator.cpp | 58 +- models/noise_generator.h | 47 +- models/poisson_generator.cpp | 2 +- models/pp_pop_psc_delta.cpp | 410 +++++++++ models/pp_pop_psc_delta.h | 400 ++++++++ models/pp_psc_delta.cpp | 114 ++- models/pp_psc_delta.h | 89 +- models/ppd_sup_generator.cpp | 22 +- models/ppd_sup_generator.h | 2 - models/pulsepacket_generator.cpp | 4 +- models/quantal_stp_connection.cpp | 194 ++++ models/quantal_stp_connection.h | 197 ++++ models/sinusoidal_poisson_generator.cpp | 4 +- models/sli/models-init.sli | 11 +- models/sli_neuron.h | 2 - models/spike_detector.cpp | 10 +- models/spike_detector.h | 26 +- models/spike_generator.cpp | 8 +- models/spike_generator.h | 5 +- models/stdp_connection.cpp | 1 - models/stdp_connection.h | 2 +- models/stdp_connection_facetshw_hom.cpp | 45 +- models/stdp_connection_facetshw_hom.h | 20 +- models/stdp_connection_hom.cpp | 35 +- models/stdp_connection_hom.h | 2 +- models/stdp_dopa_connection.h | 4 +- models/stdp_pl_connection_hom.cpp | 33 +- models/stdp_pl_connection_hom.h | 2 +- models/tsodyks2_connection.cpp | 2 +- models/tsodyks2_connection.h | 16 +- nest/Makefile.am | 23 +- nest/main.cpp | 23 +- nest/neststartup.cpp | 72 +- nest/neststartup.h | 34 +- nestkernel/Makefile.am | 10 +- nestkernel/archiving_node.cpp | 10 +- nestkernel/bg_get_mem.c | 16 + nestkernel/common_synapse_properties.cpp | 3 - nestkernel/communicator.cpp | 95 +- nestkernel/communicator.h | 22 +- nestkernel/communicator_impl.h | 1 - nestkernel/conn_builder.cpp | 782 ++++++++++++++++ nestkernel/conn_builder.h | 222 +++++ nestkernel/conn_builder_factory.h | 75 ++ nestkernel/conn_parameter.cpp | 78 ++ nestkernel/conn_parameter.h | 171 ++++ nestkernel/connection.h | 3 +- nestkernel/connection_id.cpp | 15 +- nestkernel/connection_id.h | 6 +- nestkernel/connection_manager.cpp | 118 +-- nestkernel/connection_manager.h | 1 + nestkernel/connector.h | 1 + nestkernel/connector_model.cpp | 1 - nestkernel/dynamicloader.cpp | 4 +- nestkernel/event.cpp | 1 - nestkernel/exceptions.cpp | 17 +- nestkernel/exceptions.h | 74 +- nestkernel/generic_connector.h | 36 +- nestkernel/generic_connector_model.h | 11 +- nestkernel/genericmodel.h | 13 +- nestkernel/gid_collection.cpp | 61 ++ nestkernel/gid_collection.h | 135 +++ nestkernel/model.h | 1 + nestkernel/modelrangemanager.cpp | 8 +- nestkernel/music_event_handler.cpp | 20 +- nestkernel/music_event_handler.h | 3 +- nestkernel/nest.h | 5 +- .../{connectiondatum.cpp => nest_datums.cpp} | 35 +- .../{connectiondatum.h => nest_datums.h} | 27 +- nestkernel/nest_names.cpp | 63 +- nestkernel/nest_names.h | 146 ++- nestkernel/nest_timeconverter.h | 1 - nestkernel/nestmodule.cpp | 267 ++++-- nestkernel/nestmodule.h | 103 ++- nestkernel/network.cpp | 640 ++++++++----- nestkernel/network.h | 216 ++++- nestkernel/network_impl.h | 42 + nestkernel/node.cpp | 13 +- nestkernel/node.h | 23 +- nestkernel/recordables_map.h | 6 +- nestkernel/recording_device.cpp | 25 +- nestkernel/scheduler.cpp | 651 +++++++------ nestkernel/scheduler.h | 136 ++- nestkernel/sibling_container.cpp | 92 +- nestkernel/sibling_container.h | 360 ++++---- nestkernel/stimulating_device.h | 8 +- nestkernel/subnet.cpp | 546 +++++------ nestkernel/subnet.h | 3 + nestkernel/universal_data_logger.h | 6 +- precise/iaf_psc_alpha_canon.h | 7 +- precise/iaf_psc_alpha_presc.h | 7 +- precise/iaf_psc_delta_canon.h | 2 - precise/iaf_psc_exp_ps.h | 5 +- precise/poisson_generator_ps.cpp | 11 +- precise/poisson_generator_ps.h | 2 - precise/precisemodule.h | 14 - precise/slice_ring_buffer.h | 5 +- pynest/Makefile.am | 125 ++- pynest/README.PyNEST | 23 +- pynest/checkpython.py | 8 - pynest/datumtopythonconverter.cpp | 198 ---- pynest/datumtopythonconverter.h | 113 --- pynest/do_tests.py.in | 25 +- pynest/examples/BrodyHopfield.py | 18 +- pynest/examples/CampbellSiegert.py | 12 +- .../examples}/HillTononi/ht_current.py | 4 +- .../examples}/HillTononi/ht_poisson.py | 6 +- .../LeNovere_2012/brunel2000_classes.py | 25 +- .../LeNovere_2012/brunel2000_interactive.py | 26 +- .../examples/LeNovere_2012/brunel2000_rand.py | 51 +- .../LeNovere_2012/brunel2000_rand_plastic.py | 63 +- pynest/examples/balancedneuron.py | 129 +-- pynest/examples/brunel-alpha-nest.py | 48 +- pynest/examples/brunel-alpha-numpy.py | 30 +- pynest/examples/brunel-delta-nest.py | 50 +- .../examples/brunel-exp-multisynapse-nest.py | 169 ++++ pynest/examples/csa_example.py | 25 +- pynest/examples/csa_topology_example.py | 89 ++ pynest/examples/if_curve.py | 5 +- pynest/examples/mc_neuron.py | 22 +- pynest/examples/multimeter.py | 6 +- pynest/examples/multimeter_file.py | 12 +- pynest/examples/one-neuron.py | 60 +- pynest/examples/plot_quantal_stp_synapse.py | 96 ++ pynest/examples/pulsepacket.py | 4 +- pynest/examples/repeated_stimulation.py | 6 +- pynest/examples/sinusoidal_gamma_generator.py | 2 +- .../examples/sinusoidal_poisson_generator.py | 2 +- pynest/examples/test-aeif_cond_alpha_RK5.py | 88 ++ pynest/examples/test_quantal_stp_synapse.py | 84 ++ pynest/examples/test_tsodyks2_synapse.py | 19 +- pynest/examples/testiaf.py | 4 +- pynest/examples/tsodyks_depressing.py | 44 +- pynest/examples/tsodyks_facilitating.py | 44 +- pynest/examples/twoneurons.py | 5 +- pynest/nest/__init__.py | 131 +-- pynest/nest/hl_api.py | 859 ++++++++++++------ pynest/nest/raster_plot.py | 27 +- pynest/nest/tests/__init__.py | 5 +- pynest/nest/tests/compatibility.py | 67 ++ pynest/nest/tests/decorators.py | 52 -- pynest/nest/tests/test_all.py | 57 +- .../nest/tests/test_connect_all_patterns.py | 42 + pynest/nest/tests/test_connect_all_to_all.py | 103 +++ .../nest/tests/test_connect_distributions.py | 208 +++++ .../nest/tests/test_connect_fixed_indegree.py | 151 +++ .../tests/test_connect_fixed_outdegree.py | 148 +++ .../tests/test_connect_fixed_total_number.py | 128 +++ pynest/nest/tests/test_connect_helpers.py | 459 ++++++++++ pynest/nest/tests/test_connect_one_to_one.py | 87 ++ .../tests/test_connect_pairwise_bernoulli.py | 96 ++ pynest/nest/tests/test_connect_parameters.py | 322 +++++++ pynest/nest/tests/test_connectapi.py | 231 ----- pynest/nest/tests/test_connectoptions.py | 65 -- .../test_convergent_divergent_connect.py | 123 +++ pynest/nest/tests/test_create.py | 95 +- pynest/nest/tests/test_csa.py | 126 ++- pynest/nest/tests/test_dataconnect.py | 2 + pynest/nest/tests/test_errors.py | 76 +- pynest/nest/tests/test_events.py | 6 +- pynest/nest/tests/test_findconnections.py | 8 +- pynest/nest/tests/test_getconnections.py | 67 ++ pynest/nest/tests/test_libcsa.py | 178 ++++ pynest/nest/tests/test_networks.py | 83 +- pynest/nest/tests/test_onetooneconnect.py | 144 +++ pynest/nest/tests/test_quantal_stp_synapse.py | 110 +++ pynest/nest/tests/test_stack.py | 122 ++- pynest/nest/tests/test_status.py | 207 +++-- pynest/nest/tests/test_threads.py | 27 +- pynest/nest/visualization.py | 62 +- pynest/nest/voltage_trace.py | 51 +- pynest/pydatum.cpp | 112 --- pynest/pydatum.h | 70 -- pynest/pynestkernel.cpp | 845 ----------------- pynest/pynestkernel.pxd | 187 ++++ pynest/pynestkernel.pyx | 500 ++++++++++ pynest/pynestmodule.cpp | 86 -- pynest/pynestmodule.h | 79 -- pynest/pynestpycsa.cpp | 276 ------ pynest/pynestpycsa.h | 66 -- pynest/setup.py.in | 205 +---- releasetools/buildnest.sh | 15 +- sli/Makefile.am | 98 +- sli/aggregatedatum.h | 63 +- sli/aggregatedatum_impl.h | 85 -- sli/arraydatum.cc | 5 - sli/booldatum.cc | 6 - sli/booldatum.h | 8 - sli/charcode.h | 1 + sli/datum.cc | 7 - sli/datum.h | 17 +- sli/datumconverter.h | 112 --- sli/dict.cc | 3 +- sli/dictdatum.cc | 1 - sli/dictdatum.h | 79 ++ sli/dictstack.cc | 2 +- sli/dictutils.h | 115 +++ sli/filesystem.cc | 7 +- sli/integerdatum.cc | 1 - sli/interpret.cc | 11 +- sli/interpret.h | 5 + sli/iteratordatum.h | 8 - sli/literaldatum.cc | 8 - sli/lockptrdatum.h | 58 +- sli/lockptrdatum_impl.h | 38 +- sli/name.h | 6 +- sli/namedatum.cc | 3 - sli/namedatum.h | 7 - sli/numericdatum.h | 10 - sli/numericdatum_impl.h | 15 - sli/oosupport.cc | 2 +- sli/parserdatum.h | 1 - sli/processes.cc | 14 +- sli/scanner.cc | 3 +- sli/scanner.h | 2 +- sli/sliarray.cc | 106 ++- sli/sliarray.h | 14 + sli/slicontrol.cc | 74 +- sli/slidata.cc | 79 +- sli/slidata.h | 14 + sli/slidict.cc | 12 +- sli/sliexceptions.cc | 20 + sli/sliexceptions.h | 62 +- sli/slinames.h | 6 +- sli/sliregexp.cc | 23 +- sli/slistartup.cc | 13 +- sli/slistartup.h | 3 +- sli/slitypecheck.cc | 2 +- sli/stringdatum.cc | 2 - sli/symboldatum.cc | 2 - sli/tarrayobj.cc | 4 +- sli/token.h | 8 +- sli/typechk.cc | 2 +- testsuite/README | 17 +- testsuite/do_tests.sh.in | 11 +- .../cross_check_test_mip_corrdet.py | 3 +- .../event_delivery_interference.py | 2 +- testsuite/manualtests/getnodes.sli | 22 + testsuite/manualtests/model_node_init.sli | 2 +- .../manualtests/parallel_conn_and_rand.sli | 138 +++ testsuite/manualtests/stdp_check.py | 3 +- testsuite/manualtests/stdp_dopa_check.py | 3 +- testsuite/manualtests/test_facetshw_stdp.py | 21 +- .../manualtests/test_hh_cond_exp_traub.sli | 2 +- testsuite/manualtests/test_pp_psc_delta.py | 3 +- .../test_spike_poisson_ps_base2_f.sli | 11 +- .../test_spike_poisson_ps_base2_nd.sli | 5 +- .../test_spike_poisson_ps_base2_p.sli | 9 +- testsuite/manualtests/test_stdp_dopa.py | 6 +- .../manualtests/test_tsodyks_depr_fac.py | 2 +- testsuite/manualtests/ticket-458/cuba_458.sli | 38 +- .../manualtests/ticket-458/cuba_ps_458.sli | 38 +- .../ticket-458/run_benchmark_458.sli | 38 +- .../ticket-458/run_benchmark_458_dumpVm.sli | 39 +- testsuite/manualtests/ticket-541.sli | 2 +- .../manualtests/ticket-737-DScallback.sli | 68 ++ testsuite/mpi_manualtests/run_mpi_tests.sh | 48 + .../test_mini_brunel_ps_csvp.sli | 249 +++++ .../test_mini_brunel_ps_rr.sli | 256 ++++++ .../fail/crash_distributed_assert_or_die.sli | 4 +- ...rash_distributed_collect_assert_or_die.sli | 4 +- ...sh_distributed_invariant_assert_or_die.sli | 4 +- .../fail/crash_distributed_pass_or_die.sli | 4 +- ...rocess_invariant_collect_assert_or_die.sli | 4 +- ...process_invariant_events_assert_or_die.sli | 3 +- ...d_rank_invariant_collect_assert_or_die.sli | 3 +- .../fail/fail_distributed_assert_or_die.sli | 3 +- ...fail_distributed_collect_assert_or_die.sli | 3 +- ...il_distributed_invariant_assert_or_die.sli | 3 +- .../fail/fail_distributed_pass_or_die.sli | 3 +- ...rocess_invariant_collect_assert_or_die.sli | 3 +- ...process_invariant_events_assert_or_die.sli | 4 +- ...d_rank_invariant_collect_assert_or_die.sli | 3 +- .../pass/test_distributed_assert_or_die.sli | 3 +- ...test_distributed_collect_assert_or_die.sli | 3 +- ...st_distributed_invariant_assert_or_die.sli | 3 +- .../pass/test_distributed_pass_or_die.sli | 3 +- ...rocess_invariant_collect_assert_or_die.sli | 3 +- ...process_invariant_events_assert_or_die.sli | 4 +- ...d_rank_invariant_collect_assert_or_die.sli | 3 +- .../pass/test_parse_message_line.sli | 3 +- .../mpitests/test_gamma_sup_generator.sli | 4 +- testsuite/mpitests/test_get_node_fncs.sli | 3 +- testsuite/mpitests/test_getrng_Vmset.sli | 5 +- testsuite/mpitests/test_getrng_neuron.sli | 4 +- testsuite/mpitests/test_ginzburg_neuron.sli | 4 +- testsuite/mpitests/test_global_rng.sli | 3 +- testsuite/mpitests/test_gsd.sli | 81 ++ .../mpitests/test_gsd_FixedTotalNumber.sli | 78 ++ testsuite/mpitests/test_gsd_distribution.sli | 82 ++ .../test_gsd_distribution_threaded.sli | 88 ++ testsuite/mpitests/test_gsd_threaded.sli | 83 ++ testsuite/mpitests/test_iaf_ring.sli | 7 +- testsuite/mpitests/test_mini_brunel_ps.sli | 4 +- testsuite/mpitests/test_mip_generator.sli | 4 +- testsuite/mpitests/test_neuron_vp.sli | 4 +- testsuite/mpitests/test_noise_generator.sli | 4 +- testsuite/mpitests/test_poisson_generator.sli | 4 +- .../mpitests/test_poisson_generator_ps.sli | 4 +- testsuite/mpitests/test_pp_psc_delta.sli | 4 +- testsuite/mpitests/test_ppd_sup_generator.sli | 4 +- .../mpitests/test_pulsepacket_generator.sli | 4 +- .../test_sinusoidal_gamma_generator_1.sli | 1 + .../test_sinusoidal_gamma_generator_2.sli | 2 + .../test_sinusoidal_gamma_generator_3.sli | 2 + .../test_sinusoidal_gamma_generator_4.sli | 1 + .../test_sinusoidal_poisson_generator_1.sli | 2 + .../test_sinusoidal_poisson_generator_2.sli | 2 + .../test_sinusoidal_poisson_generator_3.sli | 2 + .../test_sinusoidal_poisson_generator_4.sli | 2 + testsuite/mpitests/ticket-336-mpi.sli | 7 +- testsuite/mpitests/ticket-400.sli | 3 +- testsuite/mpitests/ticket-460.sli | 2 +- testsuite/regressiontests/ticket-156.sli | 2 +- testsuite/regressiontests/ticket-157.sli | 22 + testsuite/regressiontests/ticket-235.sli | 2 +- testsuite/regressiontests/ticket-281.sli | 2 +- testsuite/regressiontests/ticket-293.sli | 2 +- testsuite/regressiontests/ticket-310.sli | 2 +- testsuite/regressiontests/ticket-333.sli | 2 +- .../regressiontests/ticket-336-serial.sli | 2 +- testsuite/regressiontests/ticket-349.sli | 10 +- testsuite/regressiontests/ticket-382.sli | 2 +- testsuite/regressiontests/ticket-386.sli | 2 +- testsuite/regressiontests/ticket-396.sli | 5 +- testsuite/regressiontests/ticket-399.sli | 2 +- testsuite/regressiontests/ticket-414.sli | 2 +- testsuite/regressiontests/ticket-421.sli | 4 +- testsuite/regressiontests/ticket-433.sli | 4 +- testsuite/regressiontests/ticket-451.sli | 2 +- testsuite/regressiontests/ticket-452.sli | 3 +- testsuite/regressiontests/ticket-459.sli | 6 +- testsuite/regressiontests/ticket-464.sli | 2 +- testsuite/regressiontests/ticket-466.sli | 2 +- testsuite/regressiontests/ticket-475.sli | 3 +- testsuite/regressiontests/ticket-478.sli | 2 +- testsuite/regressiontests/ticket-481.sli | 3 +- testsuite/regressiontests/ticket-507.sli | 3 +- testsuite/regressiontests/ticket-514.sli | 2 +- testsuite/regressiontests/ticket-519.sli | 3 +- testsuite/regressiontests/ticket-520.sli | 3 +- testsuite/regressiontests/ticket-528.sli | 2 +- testsuite/regressiontests/ticket-537.sli | 3 +- testsuite/regressiontests/ticket-543.sli | 3 +- testsuite/regressiontests/ticket-564.sli | 8 +- testsuite/regressiontests/ticket-566.sli | 5 +- testsuite/regressiontests/ticket-580.sli | 105 +++ testsuite/regressiontests/ticket-618.sli | 10 +- testsuite/regressiontests/ticket-619.sli | 3 +- testsuite/regressiontests/ticket-638.sli | 4 +- .../regressiontests/ticket-659-copyright.py | 114 +++ testsuite/regressiontests/ticket-673.sli | 3 +- testsuite/regressiontests/ticket-716.sli | 2 + testsuite/regressiontests/ticket-733.sli | 37 + testsuite/regressiontests/ticket-748.sli | 44 + testsuite/regressiontests/ticket-754.sli | 135 +++ testsuite/regressiontests/ticket-772.sli | 73 ++ testsuite/regressiontests/ticket-777.sli | 57 ++ testsuite/regressiontests/ticket-784.sli | 45 + testsuite/regressiontests/ticket-785.sli | 49 + testsuite/regressiontests/ticket-798.sli | 56 ++ .../regressiontests/ticket-80-175-179.sli | 2 +- testsuite/selftests/test_assert_or_die_b.sli | 2 +- testsuite/selftests/test_assert_or_die_p.sli | 2 +- testsuite/selftests/test_crash_or_die.sli | 2 +- testsuite/selftests/test_fail_or_die.sli | 2 +- testsuite/selftests/test_pass_or_die.sli | 2 +- testsuite/unittests/test_DataConnect.sli | 18 +- .../unittests/test_DoubleVector_IntVector.sli | 4 +- testsuite/unittests/test_GetConnections.sli | 6 +- testsuite/unittests/test_Map.sli | 55 ++ testsuite/unittests/test_MapIndexed.sli | 49 + .../test_aeif_cond_alpha_multisynapse.sli | 172 ++++ testsuite/unittests/test_connect.sli | 168 +++- .../unittests/test_convergent_connect.sli | 2 +- testsuite/unittests/test_copymodel.sli | 2 +- testsuite/unittests/test_corr_det.sli | 2 +- testsuite/unittests/test_corr_matrix_det.sli | 216 +++++ testsuite/unittests/test_cva.sli | 53 ++ .../{test_random_custom.sli => test_cvi.sli} | 39 +- testsuite/unittests/test_dcgen_versus_I_e.sli | 2 +- testsuite/unittests/test_delay_check.sli | 2 +- .../test_dict_basic_self_reference.sli | 100 ++ testsuite/unittests/test_dirname.sli | 2 +- .../unittests/test_divergent_connect.sli | 2 +- testsuite/unittests/test_fast_operators.sli | 2 +- .../unittests/test_gamma_sup_generator.sli | 5 +- testsuite/unittests/test_getnodes.sli | 2 +- testsuite/unittests/test_iaf.sli | 2 +- testsuite/unittests/test_iaf_1to2.sli | 3 +- .../unittests/test_iaf_1to2_default_delay.sli | 2 +- testsuite/unittests/test_iaf_1to2_ex.sli | 2 +- testsuite/unittests/test_iaf_dc.sli | 2 +- testsuite/unittests/test_iaf_dc_aligned.sli | 2 +- .../test_iaf_dc_aligned_automatic.sli | 2 +- .../unittests/test_iaf_dc_aligned_delay.sli | 2 +- .../unittests/test_iaf_dc_aligned_stop.sli | 3 +- testsuite/unittests/test_iaf_fudge.sli | 2 +- testsuite/unittests/test_iaf_i0.sli | 2 +- .../unittests/test_iaf_i0_refractory.sli | 3 +- .../unittests/test_iaf_min_delay_create.sli | 2 +- .../unittests/test_iaf_min_delay_set.sli | 2 +- .../test_iaf_min_delay_simblocks.sli | 2 +- .../unittests/test_iaf_ps_dc_accuracy.sli | 2 +- .../unittests/test_iaf_ps_dc_t_accuracy.sli | 4 +- .../unittests/test_iaf_ps_psp_accuracy.sli | 2 +- .../test_iaf_ps_psp_poisson_accuracy.sli | 2 +- ..._iaf_ps_psp_poisson_generator_accuracy.sli | 3 +- ...test_iaf_ps_psp_poisson_spike_accuracy.sli | 2 +- .../test_iaf_psc_alpha_multisynapse.sli | 42 +- testsuite/unittests/test_iaf_psc_exp.sli | 2 +- .../test_iaf_psc_exp_multisynapse.sli | 40 +- testsuite/unittests/test_iaf_psp.sli | 2 +- .../unittests/test_iaf_psp_normalized.sli | 2 +- testsuite/unittests/test_iaf_psp_peak.sli | 2 +- testsuite/unittests/test_lambertw.sli | 2 +- testsuite/unittests/test_mat2.sli | 3 +- testsuite/unittests/test_max_delay.sli | 2 +- testsuite/unittests/test_message.sli | 2 +- testsuite/unittests/test_min_delay.sli | 2 +- .../unittests/test_min_delay_tics_reset.sli | 2 +- testsuite/unittests/test_mip_corrdet.sli | 2 +- testsuite/unittests/test_multimeter.sli | 2 +- testsuite/unittests/test_multimeter_accu.sli | 14 +- .../unittests/test_multimeter_freeze_thaw.sli | 7 +- .../unittests/test_multimeter_stepping.sli | 2 +- .../unittests/test_multimeter_support.sli | 2 +- .../unittests/test_multiple_multimeter.sli | 3 +- .../test_multiple_random_source_stepping.sli | 2 +- testsuite/unittests/test_multithreading.sli | 6 +- .../unittests/test_multithreading_devices.sli | 7 +- .../unittests/test_node_distribution.sli | 2 +- testsuite/unittests/test_noise_generator.sli | 2 +- .../test_poisson_generator_campbell_alpha.sli | 2 +- .../unittests/test_poisson_generator_ps.sli | 2 +- .../unittests/test_poisson_ps_intervals.sli | 2 +- .../test_poisson_ps_min_interval.sli | 6 +- testsuite/unittests/test_pp_pop_psc_delta.sli | 200 ++++ testsuite/unittests/test_pp_psc_delta.sli | 105 ++- .../unittests/test_ppd_sup_generator.sli | 5 +- .../test_psp_amplitude_consistency.sli | 2 +- .../unittests/test_pulsepacket_generator.sli | 2 +- testsuite/unittests/test_random.sli | 2 +- testsuite/unittests/test_random_binomial.sli | 2 +- testsuite/unittests/test_random_clipped.sli | 72 ++ .../test_random_convergent_connect.sli | 164 ++++ .../test_random_divergent_connect.sli | 94 +- .../unittests/test_rdv_param_setting.sli | 286 ++++++ .../unittests/test_recorder_close_flush.sli | 2 +- testsuite/unittests/test_rng_seeds.sli | 2 +- testsuite/unittests/test_round_validate.sli | 50 + testsuite/unittests/test_set_Vm.sli | 2 +- .../unittests/test_set_delay_extrema.sli | 3 +- .../unittests/test_set_start_stop_origin.sli | 2 +- testsuite/unittests/test_set_tics.sli | 5 +- .../unittests/test_setconnections_threads.sli | 5 +- .../test_sinusoidal_gamma_generator.sli | 4 +- .../test_sinusoidal_poisson_generator.sli | 6 +- testsuite/unittests/test_sli_neuron.sli | 2 +- testsuite/unittests/test_sort.sli | 2 +- testsuite/unittests/test_spike_det_reset.sli | 2 +- testsuite/unittests/test_spike_detector.sli | 5 +- testsuite/unittests/test_spike_generator.sli | 32 +- testsuite/unittests/test_spike_poisson_ps.sli | 3 +- .../unittests/test_spike_poisson_ps_base2.sli | 3 +- .../unittests/test_spike_transmission_ps.sli | 3 +- .../test_spike_transmission_ps_iaf.sli | 2 +- testsuite/unittests/test_spin_detector.sli | 12 +- testsuite/unittests/test_stdp_synapse.sli | 2 +- .../unittests/test_step_current_generator.sli | 2 +- testsuite/unittests/test_steppedsim.sli | 3 +- testsuite/unittests/test_syn_hom_wd.sli | 2 +- testsuite/unittests/test_time_input.sli | 2 +- .../unittests/test_tsodyks_depressing.sli | 11 +- .../unittests/test_tsodyks_facilitating.sli | 2 +- testsuite/unittests/test_two_devices.sli | 2 +- testsuite/unittests/test_voltmeter_reset.sli | 2 +- topology/Makefile.am | 13 +- topology/connection_creator.cpp | 17 +- topology/connection_creator.h | 65 +- topology/connection_creator_impl.h | 295 +++--- .../doc/old_doc/plotting_tools/histogram2d.py | 3 +- .../plotting_tools/plot_connections.py | 3 +- .../doc/user_manual_scripts/connections.py | 3 +- topology/doc/user_manual_scripts/layers.py | 3 +- topology/examples/conncomp.py | 11 +- topology/examples/conncon_sources.py | 7 +- topology/examples/conncon_targets.py | 3 +- topology/examples/connex.py | 3 +- topology/examples/connex_ew.py | 3 +- topology/examples/ctx_2n.py | 11 +- topology/examples/gaussex.py | 3 +- topology/examples/grid_iaf.py | 3 +- topology/examples/grid_iaf_irr.py | 3 +- topology/examples/grid_iaf_oc.py | 3 +- topology/examples/hill_tononi_Vp.py | 39 +- topology/examples/test_3d.py | 3 +- topology/examples/test_3d_exp.py | 3 +- topology/examples/test_3d_gauss.py | 3 +- topology/free_layer.h | 6 +- topology/generic_factory.h | 6 +- topology/grid_layer.h | 6 +- topology/grid_mask.h | 6 +- topology/layer.h | 10 +- topology/layer_impl.h | 46 +- topology/mask.h | 6 +- topology/mask_impl.h | 6 +- topology/ntree.h | 32 +- topology/ntree_impl.h | 10 +- topology/parameter.h | 6 +- topology/position.h | 6 +- topology/pynest/__init__.py | 32 +- topology/pynest/hl_api.py | 162 ++-- topology/pynest/tests/__init__.py | 5 +- topology/pynest/tests/test_all.py | 16 +- topology/pynest/tests/test_basics.py | 127 ++- topology/pynest/tests/test_dumping.py | 3 +- topology/pynest/tests/test_plotting.py | 15 +- .../pynest/tests/test_random_parameter.py | 36 +- topology/selector.h | 6 +- topology/setup.py.in | 20 +- topology/sli/topology-interface.sli | 2 - topology/testsuite/conntests/run_all_tests.sh | 2 + topology/testsuite/conntests/run_test.sli | 1 + .../testscripts/free_mask_circ_anchor_00.sli | 22 + .../testscripts/free_mask_circ_anchor_01.sli | 22 + .../testscripts/free_mask_circ_anchor_10.sli | 22 + .../testscripts/free_mask_circ_anchor_11.sli | 22 + .../testscripts/free_mask_donut_anchor_00.sli | 22 + .../testscripts/free_mask_donut_anchor_01.sli | 22 + .../testscripts/free_mask_donut_anchor_10.sli | 22 + .../testscripts/free_mask_donut_anchor_11.sli | 22 + .../testscripts/free_mask_rect_00.sli | 22 + .../testscripts/free_mask_rect_01.sli | 22 + .../testscripts/free_mask_rect_11.sli | 22 + .../testscripts/free_mask_rect_12.sli | 22 + .../testscripts/free_mask_rect_13.sli | 22 + .../testscripts/reg_mask_circ_anchor_00.sli | 22 + .../testscripts/reg_mask_circ_anchor_01.sli | 22 + .../testscripts/reg_mask_circ_anchor_10.sli | 22 + .../testscripts/reg_mask_circ_anchor_11.sli | 22 + .../testscripts/reg_mask_donut_anchor_00.sli | 22 + .../testscripts/reg_mask_donut_anchor_01.sli | 22 + .../testscripts/reg_mask_donut_anchor_10.sli | 22 + .../testscripts/reg_mask_donut_anchor_11.sli | 22 + .../testscripts/reg_mask_grid_anchor_00.sli | 22 + .../testscripts/reg_mask_grid_anchor_01.sli | 22 + .../testscripts/reg_mask_grid_anchor_02.sli | 22 + .../testscripts/reg_mask_grid_anchor_03.sli | 22 + .../testscripts/reg_mask_grid_anchor_04.sli | 22 + .../testscripts/reg_mask_grid_anchor_05.sli | 22 + .../testscripts/reg_mask_grid_anchor_06.sli | 22 + .../testscripts/reg_mask_grid_anchor_10.sli | 22 + .../testscripts/reg_mask_grid_anchor_11.sli | 22 + .../testscripts/reg_mask_grid_anchor_13.sli | 22 + .../testscripts/reg_mask_grid_anchor_15.sli | 22 + .../testscripts/reg_mask_rect_00.sli | 22 + .../testscripts/reg_mask_rect_01.sli | 22 + .../testscripts/reg_mask_rect_02.sli | 22 + .../testscripts/reg_mask_rect_10.sli | 22 + .../testscripts/reg_mask_rect_11.sli | 22 + .../testscripts/test_weight_delay.sli | 22 + .../testscripts/test_weight_delay_free.sli | 22 + topology/testsuite/mpitests/speed.py | 3 +- topology/testsuite/mpitests/ticket-516.py | 3 +- topology/testsuite/mpitests/topo_mpi_test.py | 5 +- .../testsuite/unittests/test_distance.sli | 3 +- .../unittests/test_oversize_mask.sli | 2 +- .../unittests/test_rows_cols_pos.sli | 2 +- topology/topology_names.h | 6 +- topology/topologymodule.cpp | 15 +- topology/topologymodule.h | 6 +- topology/vose.cpp | 2 +- topology/vose.h | 6 +- 748 files changed, 27515 insertions(+), 10529 deletions(-) rename doc/{copyright_header.txt => copyright_header.cpp} (97%) create mode 100644 doc/copyright_header.py rename examples/MyModule/sli/{mymodule.sli => mymodule-init.sli} (90%) create mode 100644 examples/nest/Potjans_2014/README.txt create mode 100644 examples/nest/Potjans_2014/microcircuit.sli create mode 100644 examples/nest/Potjans_2014/network_params.sli create mode 100644 examples/nest/Potjans_2014/plot_rates.py create mode 100755 examples/nest/Potjans_2014/run_microcircuit.sh create mode 100644 examples/nest/Potjans_2014/sim_params.sli create mode 100644 examples/nest/Potjans_2014/spike_analysis_www.py create mode 100644 examples/nest/Potjans_2014/user_params.sli create mode 100644 examples/nest/brunel-2000_newconnect.sli create mode 100644 examples/nest/music/minimalmusicsetup-pynest.music create mode 100755 examples/nest/music/minimalmusicsetup_receivenest.py create mode 100755 examples/nest/music/minimalmusicsetup_sendnest.py rename {pynest/nest => examples/neuronview}/neuronview.glade (100%) rename {pynest/nest => examples/neuronview}/neuronview.py (92%) delete mode 100644 extras/ConnPlotter/LICENSE.ConnPlotter create mode 100644 extras/automake-pre-1.14-fix.patch rename lib/sli/{arr.sli => arraylib.sli} (91%) delete mode 100644 lib/sli/version.sli delete mode 100644 libnestutil/connection_generator.cpp delete mode 100644 libnestutil/connection_generator.h create mode 100644 librandom/clipped_randomdev.h create mode 100644 librandom/librandom_exceptions.h create mode 100644 librandom/lognormal_randomdev.cpp create mode 100644 librandom/lognormal_randomdev.h create mode 100644 librandom/uniform_randomdev.cpp create mode 100644 librandom/uniform_randomdev.h create mode 100644 models/aeif_cond_alpha_RK5.cpp create mode 100644 models/aeif_cond_alpha_RK5.h create mode 100644 models/aeif_cond_alpha_multisynapse.cpp create mode 100644 models/aeif_cond_alpha_multisynapse.h create mode 100644 models/correlomatrix_detector.cpp create mode 100644 models/correlomatrix_detector.h create mode 100644 models/iaf_chs_2007.cpp create mode 100644 models/iaf_chs_2007.h create mode 100644 models/iaf_chxk_2008.cpp create mode 100644 models/iaf_chxk_2008.h create mode 100755 models/pp_pop_psc_delta.cpp create mode 100755 models/pp_pop_psc_delta.h create mode 100644 models/quantal_stp_connection.cpp create mode 100644 models/quantal_stp_connection.h create mode 100644 nestkernel/conn_builder.cpp create mode 100644 nestkernel/conn_builder.h create mode 100644 nestkernel/conn_builder_factory.h create mode 100644 nestkernel/conn_parameter.cpp create mode 100644 nestkernel/conn_parameter.h create mode 100644 nestkernel/gid_collection.cpp create mode 100644 nestkernel/gid_collection.h rename nestkernel/{connectiondatum.cpp => nest_datums.cpp} (51%) rename nestkernel/{connectiondatum.h => nest_datums.h} (63%) create mode 100644 nestkernel/network_impl.h delete mode 100644 pynest/checkpython.py delete mode 100644 pynest/datumtopythonconverter.cpp delete mode 100644 pynest/datumtopythonconverter.h rename {examples/nest => pynest/examples}/HillTononi/ht_current.py (97%) rename {examples/nest => pynest/examples}/HillTononi/ht_poisson.py (95%) mode change 100755 => 100644 pynest/examples/balancedneuron.py create mode 100644 pynest/examples/brunel-exp-multisynapse-nest.py create mode 100644 pynest/examples/csa_topology_example.py create mode 100644 pynest/examples/plot_quantal_stp_synapse.py create mode 100644 pynest/examples/test-aeif_cond_alpha_RK5.py create mode 100644 pynest/examples/test_quantal_stp_synapse.py mode change 100755 => 100644 pynest/examples/test_tsodyks2_synapse.py create mode 100644 pynest/nest/tests/compatibility.py delete mode 100644 pynest/nest/tests/decorators.py create mode 100644 pynest/nest/tests/test_connect_all_patterns.py create mode 100644 pynest/nest/tests/test_connect_all_to_all.py create mode 100644 pynest/nest/tests/test_connect_distributions.py create mode 100644 pynest/nest/tests/test_connect_fixed_indegree.py create mode 100644 pynest/nest/tests/test_connect_fixed_outdegree.py create mode 100644 pynest/nest/tests/test_connect_fixed_total_number.py create mode 100644 pynest/nest/tests/test_connect_helpers.py create mode 100644 pynest/nest/tests/test_connect_one_to_one.py create mode 100644 pynest/nest/tests/test_connect_pairwise_bernoulli.py create mode 100644 pynest/nest/tests/test_connect_parameters.py delete mode 100644 pynest/nest/tests/test_connectapi.py delete mode 100644 pynest/nest/tests/test_connectoptions.py create mode 100644 pynest/nest/tests/test_convergent_divergent_connect.py create mode 100644 pynest/nest/tests/test_getconnections.py create mode 100644 pynest/nest/tests/test_libcsa.py create mode 100644 pynest/nest/tests/test_onetooneconnect.py create mode 100644 pynest/nest/tests/test_quantal_stp_synapse.py delete mode 100644 pynest/pydatum.cpp delete mode 100644 pynest/pydatum.h delete mode 100644 pynest/pynestkernel.cpp create mode 100644 pynest/pynestkernel.pxd create mode 100644 pynest/pynestkernel.pyx delete mode 100644 pynest/pynestmodule.cpp delete mode 100644 pynest/pynestmodule.h delete mode 100644 pynest/pynestpycsa.cpp delete mode 100644 pynest/pynestpycsa.h delete mode 100644 sli/aggregatedatum_impl.h delete mode 100644 sli/datumconverter.h create mode 100644 testsuite/manualtests/parallel_conn_and_rand.sli create mode 100644 testsuite/manualtests/ticket-737-DScallback.sli create mode 100755 testsuite/mpi_manualtests/run_mpi_tests.sh create mode 100644 testsuite/mpi_manualtests/test_mini_brunel_ps_csvp.sli create mode 100644 testsuite/mpi_manualtests/test_mini_brunel_ps_rr.sli create mode 100644 testsuite/mpitests/test_gsd.sli create mode 100644 testsuite/mpitests/test_gsd_FixedTotalNumber.sli create mode 100644 testsuite/mpitests/test_gsd_distribution.sli create mode 100644 testsuite/mpitests/test_gsd_distribution_threaded.sli create mode 100644 testsuite/mpitests/test_gsd_threaded.sli create mode 100644 testsuite/regressiontests/ticket-580.sli create mode 100644 testsuite/regressiontests/ticket-659-copyright.py create mode 100644 testsuite/regressiontests/ticket-733.sli create mode 100644 testsuite/regressiontests/ticket-748.sli create mode 100644 testsuite/regressiontests/ticket-754.sli create mode 100644 testsuite/regressiontests/ticket-772.sli create mode 100644 testsuite/regressiontests/ticket-777.sli create mode 100644 testsuite/regressiontests/ticket-784.sli create mode 100644 testsuite/regressiontests/ticket-785.sli create mode 100644 testsuite/regressiontests/ticket-798.sli create mode 100644 testsuite/unittests/test_Map.sli create mode 100644 testsuite/unittests/test_MapIndexed.sli create mode 100644 testsuite/unittests/test_aeif_cond_alpha_multisynapse.sli create mode 100644 testsuite/unittests/test_corr_matrix_det.sli create mode 100644 testsuite/unittests/test_cva.sli rename testsuite/unittests/{test_random_custom.sli => test_cvi.sli} (50%) create mode 100644 testsuite/unittests/test_dict_basic_self_reference.sli create mode 100755 testsuite/unittests/test_pp_pop_psc_delta.sli create mode 100644 testsuite/unittests/test_random_clipped.sli create mode 100644 testsuite/unittests/test_random_convergent_connect.sli create mode 100644 testsuite/unittests/test_rdv_param_setting.sli create mode 100644 testsuite/unittests/test_round_validate.sli mode change 100755 => 100644 topology/doc/old_doc/plotting_tools/histogram2d.py mode change 100755 => 100644 topology/doc/old_doc/plotting_tools/plot_connections.py diff --git a/Makefile.am b/Makefile.am index d8de08c3f0..ad424096d0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -20,7 +20,8 @@ dist-hook: rm -rf $(distdir)/doc/doxygen rm -f $(distdir)/doc/doxygen.log rm -rf $(distdir)/examples/nest/FacetsBenchmarks/debugging_versions - rm -f $(distdir)/libltdl/{config.h,config.log,config.status,Makefile,stamp-h1} + rm -f $(distdir)/libltdl/{config.h,config.log,config.status,Makefile,stamp-h1,libtool} + rm -rf $(distdir)/libltdl/.deps rm -f $(distdir)/extras/logos/*.{ai,svg} rm -f $(distdir)/extras/logos/nest-initiative-logo*.* @@ -52,15 +53,16 @@ endif if HAVE_PYTHON +# Python interpreter is discovered by AM_PATH_PYTHON and declared as a make variable by AC_SUBST installcheck-local: - PATH=$(exec_prefix)/bin:$(PATH) \ - /bin/sh $(DESTDIR)@PKGDATADIR@/extras/do_tests.sh --test-pynest + PATH="$(exec_prefix)/bin:$(PATH)" PYTHON="$(PYTHON)" PYTHONPATH="$(pyexecdir):$(PYTHONPATH)" \ + /bin/sh $(DESTDIR)@PKGDATADIR@/extras/do_tests.sh --test-pynest --source-dir=$(top_srcdir) else installcheck-local: - PATH=$(exec_prefix)/bin:$(PATH) \ - /bin/sh $(DESTDIR)@PKGDATADIR@/extras/do_tests.sh + PATH="$(exec_prefix)/bin:$(PATH)" \ + /bin/sh $(DESTDIR)@PKGDATADIR@/extras/do_tests.sh --source-dir=$(top_srcdir) endif diff --git a/acinclude.m4 b/acinclude.m4 index 6c08a781ab..bad3c2b07c 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -62,7 +62,6 @@ echo "Platform: ${host}" if test "${compversion:0:4}" = "icpc"; then # Intel compiler pretending to be g++ echo "Compiler : icpc" - SLI_pynest_cxxflags="-fpermissive" if test "$SLI_debug" = "set" -a -z "$SLI_debugflags"; then SLI_debugflags="-g -inline-debug-info" fi @@ -75,7 +74,6 @@ echo "Platform: ${host}" else #real g++ echo "Compiler : g++" - SLI_pynest_cxxflags="-fpermissive" if test "$SLI_debug" = "set" -a -z "$SLI_debugflags"; then SLI_debugflags="-g" fi @@ -89,7 +87,6 @@ echo "Platform: ${host}" fi if test "x$enable_bluegene" = xyes; then echo "Compiling for the Blue Gene using compilers specified by CC and CXX environment variables" - SLI_pynest_cxxflags=" " if test "$SLI_debug" = "set"; then SLI_debugflags=" " fi @@ -105,7 +102,6 @@ echo "Platform: ${host}" SLI_forte=`$CXX -V 2>&1 | grep Forte` if test "$GXX" = "yes"; then echo "Compiler : g++" - SLI_pynest_cxxflags="-fpermissive" if test "$SLI_debug" = "set" -a -z "$SLI_debugflags"; then SLI_debugflags="-g" fi @@ -155,7 +151,6 @@ echo "Platform: ${host}" *-hp-hpux*) if test "$GXX" = "yes"; then echo "Compiler : g++" - SLI_pynest_cxxflags="-fpermissive" if test "$SLI_debug" = "set" -a -z "$SLI_debugflags"; then SLI_debugflags="-g" fi @@ -172,7 +167,6 @@ echo "Platform: ${host}" mips-sgi-irix*) if test "$GXX" = "yes"; then echo "Compiler : g++" - SLI_pynest_cxxflags="-fpermissive" if test "$SLI_debug" = "set" -a -z "$SLI_debugflags"; then SLI_debugflags="-g" fi @@ -198,7 +192,6 @@ echo "Platform: ${host}" *-dec-osf*) if test "$GXX" = "yes"; then echo "Compiler : g++" - SLI_pynest_cxxflags="-fpermissive" if test "$SLI_debug" = "set" -a -z "$SLI_debugflags"; then SLI_debugflags="-g" fi @@ -225,7 +218,6 @@ echo "Platform: ${host}" hppa1.1-hitachi-hiuxwe2*) if test "$GXX" = "yes"; then echo "Compiler : g++" - SLI_pynest_cxxflags="-fpermissive" if test "$SLI_debug" = "set" -a -z "$SLI_debugflags"; then SLI_debugflags="-g" fi @@ -253,7 +245,6 @@ echo "Platform: ${host}" powerpc-ibm-aix5.1*) if test "$GXX" = "yes"; then echo "Compiler : g++" - SLI_pynest_cxxflags="-fpermissive" if test "$SLI_debug" = "set" -a -z "$SLI_debugflags"; then SLI_debugflags="-g" fi @@ -282,7 +273,6 @@ echo "Platform: ${host}" ## For all other OS, we just check for the GNU compiler. if test "$GXX" = "yes"; then echo "Compiler : g++" - SLI_pynest_cxxflags="-fpermissive" if test "$SLI_debug" = "set" -a -z "$SLI_debugflags"; then SLI_debugflags="-g" fi @@ -302,13 +292,10 @@ echo "Platform: ${host}" ## CXXFLAGS now appended instead of prepended, so that it can ## override default values. AM_CXXFLAGS="$SLI_threadflags $SLI_cxxflags $SLI_warningflags $SLI_debugflags $SLI_optimizeflags $SLI_SAVE_CXXFLAGS" -PYNEST_CXXFLAGS="$SLI_pynest_cxxflags" echo "Using AM_CXXFLAGS= $AM_CXXFLAGS" -echo "Using PYNEST_CXXFLAGS= $PYNEST_CXXFLAGS" AC_SUBST(SLI_CXXBACKEND) AC_SUBST(AM_CXXFLAGS) -AC_SUBST(PYNEST_CXXFLAGS) AC_SUBST(CXX_AR) ]) @@ -388,7 +375,6 @@ echo "Platform: ${host}" fi if test "x$enable_bluegene" = xyes; then echo "Compiling for the Blue Gene using compilers specified by CC and CXX environment variables" - SLI_pynest_cxxflags=" " if test "$SLI_debug" = "set"; then SLI_debugflags=" " fi @@ -1513,6 +1499,65 @@ if test "$hep_cv_cxx_specialization_bug" = yes; then fi ]) +dnl @synopsis SLI_CHECK_XLC_ICE_ON_USING +dnl +dnl Tests for a an internal compiler error obeserved in IBM xlC. +dnl If bug the ICE is detected, defines +dnl HAVE_XLC_ICE_ON_USING +dnl +dnl @author Hans E. Plesser +dnl + +AC_DEFUN([SLI_CHECK_XLC_ICE_ON_USING], +[AC_CACHE_CHECK(whether the compiler fails with ICE, +hep_cv_xlc_ice_on_using, +[AC_LANG_SAVE + AC_LANG_CPLUSPLUS + AC_TRY_LINK([ +class RandomDev +{ +public: + virtual double operator()(void) =0; + virtual double operator()(double x) =0; +}; + +class GenericRandomDevFactory +{ +public: + virtual RandomDev* create() const =0; +}; + +template +class RandomDevFactory: public GenericRandomDevFactory +{ +public: + RandomDev* create() const + { + return new DevType(); + } +}; + +template +class Wrapper: public T +{ +public: + using RandomDev::operator(); + double operator()(void) { return 0.0; } + double operator()(double x) { return x; } +}; +], +[ +RandomDevFactory > r; +], + hep_cv_xlc_ice_on_using=no, hep_cv_xlc_ice_on_using=yes) + AC_LANG_RESTORE +]) +if test "$hep_cv_xlc_ice_on_using" = yes; then + AC_DEFINE(HAVE_XLC_ICE_ON_USING,, + [define if the compiler fails with ICE]) +fi +]) + # SLI_C_INLINE # ------------ # Do nothing if the compiler accepts the inline keyword. @@ -1607,4 +1652,75 @@ AC_DEFUN([SLI_CHECK_SOURCE_FILE], else $3 fi -]) \ No newline at end of file +]) + +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS]) +# +# DESCRIPTION +# +# Check whether the given FLAG works with the current language's compiler +# or gives an error. (Warnings, however, are ignored) +# +# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on +# success/failure. +# +# If EXTRA-FLAGS is defined, it is added to the current language's default +# flags (e.g. CFLAGS) when the check is done. The check is thus made with +# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to +# force the compiler to issue an error when a bad flag is given. +# +# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this +# macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG. +# +# LICENSE +# +# Copyright (c) 2008 Guido U. Draheim +# Copyright (c) 2011 Maarten Bosmans +# +# 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 . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +AC_DEFUN([AX_CHECK_COMPILE_FLAG], +[AC_PREREQ(2.59)dnl for _AC_LANG_PREFIX +AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl +AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ + ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS + _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM()], + [AS_VAR_SET(CACHEVAR,[yes])], + [AS_VAR_SET(CACHEVAR,[no])]) + _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags]) +AS_IF([test x"AS_VAR_GET(CACHEVAR)" = xyes], + [m4_default([$2], :)], + [m4_default([$3], :)]) +AS_VAR_POPDEF([CACHEVAR])dnl +])dnl AX_CHECK_COMPILE_FLAGS diff --git a/bootstrap.sh b/bootstrap.sh index 4c11d022db..dcac1e3a09 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -27,7 +27,7 @@ fi libtool_major=`$LIBTOOLIZE --version | head -n1 | cut -d\) -f2 | cut -d\. -f1` if test $libtool_major -lt 2; then - echo " -> Patching configure.ac for libtoolize 1.5..." + echo " -> Patching configure.ac for libtoolize 1.5 ..." patch -s -f -p0 < extras/libtool-1.5-fix.patch $LIBTOOLIZE --force --copy --ltdl else @@ -35,11 +35,7 @@ else fi echo " -> Re-running aclocal ..." -if test $libtool_major -le 2; then - aclocal --force -else - aclocal --force -I $pwd/libltdl/m4 -fi +aclocal --force echo " -> Running autoconf ..." autoconf @@ -48,6 +44,14 @@ autoconf echo " -> Running autoheader ..." autoheader +# patch configure.ac for old (pre 1.14) versions of automake +am_major=`automake --version | head -n1 | cut -d\) -f2 | cut -d. -f1` +am_minor=`automake --version | head -n1 | cut -d. -f2` +if test $am_major -lt 1 -o \( $am_major -le 1 -a $am_minor -lt 14 \); then + echo " -> Patching configure.ac for automake < 1.14 ..." + patch -s -f -p0 < extras/automake-pre-1.14-fix.patch +fi + echo " -> Running automake ..." automake --foreign --add-missing --force-missing --copy diff --git a/configure.ac.in b/configure.ac.in index a1141e5eff..36e0aa939c 100644 --- a/configure.ac.in +++ b/configure.ac.in @@ -6,14 +6,21 @@ # AC_PREREQ(2.52) -AC_INIT([nest], [2.2.svn], [nest_user@nest-initiative.org]) +AC_INIT([nest], [2.4.0], [nest_user@nest-initiative.org]) + +# Prevent automatic rebuilding of Makefile.ins and configure if their +# content or timestamp changes. Not doing this lead to failing builds +# from tarballs on platforms with older versions of autotools. See +# stackoverflow.com/questions/18769770 for the problem. Rebuilding can +# still be enabled by configuring with --enable-maintainer-mode. +AM_MAINTAINER_MODE([disable]) # These variables are exported to libnestutil/config.h # The patchlevel is updated automatically by the script # releasetools/buildnest SLI_MAJOR=2 -SLI_MINOR=2 -SLI_PATCHLEVEL=svn +SLI_MINOR=4 +SLI_PATCHLEVEL=0 SLI_PRGNAME="nest-$SLI_MAJOR.$SLI_MINOR.$SLI_PATCHLEVEL" SLI_VERSION=$SLI_MAJOR.$SLI_MINOR.$SLI_PATCHLEVEL @@ -41,7 +48,7 @@ AC_CONFIG_AUX_DIR(.) # We might consider switching to tar-pax (2001) in the future, for now # tar-ustar (1988) is probably good enough. tar-v7 is not an option, since # we already hit the 99 char filename limit. -AM_INIT_AUTOMAKE([tar-ustar]) +AM_INIT_AUTOMAKE([tar-ustar subdir-objects]) # Allow to build NEST using silent rules. m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES]) @@ -49,6 +56,9 @@ m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES]) # Obtain host system type; HEP 2004-12-20 AC_CANONICAL_HOST +# This is necessary to use AC_CHECK_HEADER +AC_USE_SYSTEM_EXTENSIONS + # ------------------------------------------------------------------------ # Handle options # @@ -128,13 +138,14 @@ AC_ARG_WITH(vampir,[ --with-vampir Include support for the Vampir tool.], fi]) -configure_bluegene="no" + bluegene_architecture="none" +configure_bluegene="no" AC_MSG_CHECKING(whether we are configuring for Blue Gene) AC_ARG_ENABLE([bluegene], [AS_HELP_STRING([--enable-bluegene], [Configure for Blue Gene; the specific BG model must be given as argument (=L/P/Q).])], - [if test "x$enableval" != xno ; then + [if test "x$enableval" != "xno" ; then configure_bluegene="yes" enableval_uc=`echo ${enableval} | awk {'print toupper($_)'}` if test "x$enableval_uc" = xL || test "x$enableval_uc" = xP || test "x$enableval_uc" = xQ; then @@ -248,6 +259,32 @@ AC_ARG_WITH(music,[ --with-music[[=directory]] Request the use of MUSIC. fi ]) +# +# Use libneurosim? +# +AC_CHECK_LIB(neurosim, libneurosim_version, HAVE_LIBNEUROSIM="auto", HAVE_LIBNEUROSIM="no") +if test "x$HAVE_LIBNEUROSIM" = xauto; then + LIBNEUROSIM_LIBS="-lneurosim" + LIBNEUROSIM_PY_LIBS="-lpyneurosim" + LIBNEUROSIM_INCLUDE="" +fi +AC_ARG_WITH(libneurosim, [ --with-libneurosim[[=directory]] Request the use of libneurosim. Optionally give the directory, where libneurosim is installed], + [ + if test "$withval" != "no"; then + if test "$withval" != "yes"; then + LIBNEUROSIM_LIBS="-L${withval}/lib -lneurosim" + LIBNEUROSIM_PY_LIBS="-lpyneurosim" + LIBNEUROSIM_INCLUDE="-I${withval}/include" + fi + HAVE_LIBNEUROSIM="yes" + else + HAVE_LIBNEUROSIM="no" + fi + ]) + +if test "x$HAVE_LIBNEUROSIM" != xno; then + AC_DEFINE(HAVE_LIBNEUROSIM, 1, [libneurosim support enabled?]) +fi # Select optimization mode # note: see debugging mode selection @@ -390,65 +427,6 @@ else fi # further processing of distributed case below (see SLI_NEW_PATH_MPI) - -# disable PyNEST for Blue Gene or if explicitly stated -AC_MSG_CHECKING([whether to compile PyNEST]) -if test "x$configure_bluegene" = xyes ; then - HAVE_PYTHON=no -else - HAVE_PYTHON=yes - PYTHON_EXEC=`which python` - - AC_ARG_WITH(python,[ --with-python=python specify the Python interpreter to use], - [ - if test "$withval" == no; then - HAVE_PYTHON=no - else - if test "$withval" != yes; then - PYTHON_EXEC=$withval - fi - fi - ]) -fi -AC_MSG_RESULT([$HAVE_PYTHON]) - -# Check, whether we are able to compile PyNEST. This will break, if no Python -# interpreter is found. -# JME 2008/04 -if test $HAVE_PYTHON = yes; then - AC_CHECK_FILE($PYTHON_EXEC, HAVE_PYTHON=yes, AC_MSG_ERROR([Python interpreter '$PYTHON_EXEC' not found.])) - PYTHON_VERSION=`$PYTHON_EXEC -c "from distutils import sysconfig;\ - print sysconfig.get_python_version()"` - - PYNEST_SUBDIR="pynest" - - AC_MSG_CHECKING([for Python headers]) - PYTHON_INC_PATH="`$PYTHON_EXEC $PKGSRCDIR/$PYNEST_SUBDIR/checkpython.py`" - if test $PYTHON_INC_PATH != "yes"; then - AC_MSG_RESULT([no]) - AC_MSG_ERROR([Python headers not found. Make sure you have the development package installed. - If you do not need PyNEST, use --without-python to disable it.]) - fi - AC_MSG_RESULT([yes]) - - if test $exec_prefix = NONE; then - PYNEST_PREFIX=${prefix} - else - PYNEST_PREFIX=${exec_prefix} - fi - - # Check for a non-standard installation path for PyNEST - AC_ARG_WITH(pynest-prefix,[ --with-pynest-prefix=path install PyNEST to path/lib/python/site-packages.], - [ - PYNEST_PREFIX=$withval - ]) -fi - -# register variable HAVE_PYTHON to be visible in Makefile.am -# required to run or not run the PyNEST tests in the testsuite -AM_CONDITIONAL(HAVE_PYTHON, test "x$HAVE_PYTHON" != xno) - - ##-- use ltdl library for dynamic loading of modules ## if not Cygwin or blue gene AC_MSG_CHECKING([whether to build shared libraries]) @@ -608,7 +586,7 @@ AC_PATH_PROGS([MAKE],[gmake make],[make]) SLI_LIBS="$SLI_LIBS $LDFLAGS" # Check for readline if not configuring for Blue Gene -if test "x$configure_bluegene" = xno ; then +if test "x$configure_bluegene" = "xno" ; then AC_ARG_WITH([readline], [AS_HELP_STRING([--without-readline], [disable support for GNU readline])], [], [with_readline=yes]) @@ -626,6 +604,8 @@ if test "x$configure_bluegene" = xno ; then [AC_MSG_ERROR([No readline found, --without-readline to disable])],\ [${SLI_LIBS}]) fi +else + AC_MSG_WARN("Skipping configuration of libreadline") fi # Test if to use multithreading with either OpenMP or POSIX threads @@ -692,8 +672,50 @@ else AC_MSG_RESULT(none) fi fi + +AM_CONDITIONAL([LINK_PTHREAD], test "x$with_pthread" = xyes) +AM_CONDITIONAL([LINK_OPENMP], test "x$with_openmp" = xyes) + # End of thread library processing +AC_ARG_WITH([python], + [AS_HELP_STRING([--without-python], [ignore the presence of Python and disable PyNEST])]) + +AS_IF([test "x$with_python" != "xno"], + [AM_PATH_PYTHON([2.6], [have_python=yes], [have_python=no])], + [have_python=no]) + +AS_IF([test "x$have_python" = "xyes"], [ + PYTHON_INC=`$PYTHON -c 'import sys; from distutils import sysconfig; sys.stdout.write(sysconfig.get_python_inc())'` + AC_CHECK_FILE(["${PYTHON_INC}/Python.h"], [PYNEST_CPPFLAGS="-I${PYTHON_INC}"], [have_python=no]) +]) + +AC_MSG_CHECKING([whether to build PyNEST]) +AS_IF([test "x$have_python" = "xyes"], [], + [AS_IF([test "x$with_python" = "xyes"], + [AC_MSG_ERROR([PyNEST requested, but Python not found])])]) +AC_MSG_RESULT([$have_python]) + +AX_CHECK_COMPILE_FLAG([-fno-strict-aliasing], + [PYNEST_CXXFLAGS="-fno-strict-aliasing"], []) + +# FIXME: this means that --without-python make will not recurse into pynest subdir +if test "x$have_python" = "xyes"; then + PYNEST_SUBDIR="pynest" +else + PYNEST_SUBDIR="" +fi + +AM_CONDITIONAL([HAVE_PYTHON], [test "x$have_python" = "xyes"]) + +AC_SUBST([HAVE_PYTHON]) +AC_SUBST([PYNEST_SUBDIR]) + +AC_SUBST([PYTHON]) +AC_SUBST([PYTHON_VERSION]) + +AC_SUBST([PYNEST_CPPFLAGS]) +AC_SUBST([PYNEST_CXXFLAGS]) # is long long available for type representation and fully usable? SLI_HAVE_LONG_LONG @@ -742,6 +764,8 @@ SLI_CHECK_SSTREAM_HEADER SLI_CHECK_STL_VECTOR_CAPACITY_BASE_UNITY SLI_CHECK_STL_VECTOR_CAPACITY_DOUBLING +SLI_CHECK_XLC_ICE_ON_USING + SLI_CHECK_EXITCODES # ---------------------------------------------------- @@ -780,12 +804,16 @@ fi # - SLI_NONPUBLIC_DYNMODULES # dynamically linked, automatically loaded, not included in release -SLI_PUBLIC_MODULES="models precise topology conngen" +SLI_PUBLIC_MODULES="models precise topology" SLI_NONPUBLIC_MODULES="" SLI_PUBLIC_DYNMODULES="" SLI_NONPUBLIC_DYNMODULES="" +if test "x$HAVE_LIBNEUROSIM" != xno; then + SLI_PUBLIC_MODULES="$SLI_PUBLIC_MODULES conngen" +fi + # Now go through all candidates and set up necessary variables and directories # NOTE: We only include those modules that shall be loaded automatically. # The _NOLOAD modules will only be included with the SUBDIRS below. @@ -850,13 +878,13 @@ done # This way of doing it is quite a hack. We cannot use AC_CONFIG_FILES(), since # we cannot AC_SUBST() the multiline variables we create here. AC_CONFIG_COMMANDS([nest/static_modules.h], - [printf "#ifndef STATIC_MODULES_H\n#define STATIC_MODULES_H\n\n$acc_include_static_modules\n#include \"interpret.h\"\n#include \"network.h\"\n\nvoid add_static_modules(SLIInterpreter& engine, nest::Network& net)\n{\n$acc_add_static_modules\n}\n#endif\n" > nest/static_modules.h], + [printf "#ifndef STATIC_MODULES_H\n#define STATIC_MODULES_H\n\n$acc_include_static_modules\n#include \"interpret.h\"\n#include \"network.h\"\n\nvoid add_static_modules(SLIInterpreter& engine, nest::Network& net)\n{\n$acc_add_static_modules}\n\n#endif\n" > nest/static_modules.h], [acc_include_static_modules='$INCLUDE_STATIC_MODULES' acc_add_static_modules='$ADD_STATIC_MODULES']) # directories to include in distribution tarballs SLI_CORE_LIBS="libnestutil sli librandom lib nestkernel $SLI_PUBLIC_MODULES $SLI_PUBLIC_DYNMODULES" -SLI_DIST_SUBDIRS="$SLI_CORE_LIBS nest $PYNEST_SUBDIR" +SLI_DIST_SUBDIRS="$SLI_CORE_LIBS nest conngen pynest" SLI_SUBDIRS="$SLI_CORE_LIBS $SLI_EXTRA_MODULES nest" # generate a list of absolute paths where to search for help files @@ -946,17 +974,16 @@ AC_SUBST(MPI_INCLUDE) AC_SUBST(HAVE_MUSIC) AC_SUBST(MUSIC_LIBS) AC_SUBST(MUSIC_INCLUDE) +AC_SUBST(LIBNEUROSIM_LIBS) +AC_SUBST(LIBNEUROSIM_PY_LIBS) +AC_SUBST(LIBNEUROSIM_INCLUDE) AC_SUBST(INCLTDL) AC_SUBST(LIBLTDL) AC_SUBST(HAVE_LIBLTDL) AC_SUBST(LIBADD_DL) AC_SUBST(LINKED_MODULES) AC_SUBST(LINKED_USER_MODULES) -AC_SUBST(PYTHON_EXEC) -AC_SUBST(PYTHON_VERSION) -AC_SUBST(PYNEST_PREFIX) -AC_SUBST(PYNEST_SUBDIR) -AC_SUBST(HAVE_PYTHON) + AC_CONFIG_HEADER(libnestutil/config.h) AC_CONFIG_FILES(libnestutil/sliconfig.h) @@ -975,6 +1002,12 @@ AC_CONFIG_FILES(nest/Makefile) AC_CONFIG_FILES(extras/nest-config) AC_CONFIG_FILES(testsuite/do_tests.sh) +# conngen is special in that it might be omitted from build when +# libneurosim is not present, yet it always has to be configured +# in order to be distributed with the tarballs +# +AC_CONFIG_FILES(conngen/Makefile) + # In the following loop, we need to have # a case statement and list all directories # with Makefile.am explicitly. Otherwise, @@ -987,12 +1020,9 @@ for dir in $NEED_MAKEFILE_DIRS; do precise) AC_CONFIG_FILES(precise/Makefile) ;; - conngen) - AC_CONFIG_FILES(conngen/Makefile) - ;; topology) AC_CONFIG_FILES(topology/Makefile) - if test "$HAVE_PYTHON" = yes; then + if test "x$have_python" = "xyes" ; then AC_CONFIG_FILES(topology/setup.py) fi ;; @@ -1005,10 +1035,11 @@ done EXTRAS_SUBDIRS= # if Python is found, configure and compile PyNEST -if test "$HAVE_PYTHON" = yes; then +if test "x$have_python" = "xyes" ; then AC_CONFIG_FILES(pynest/Makefile) AC_CONFIG_FILES(pynest/setup.py) AC_CONFIG_FILES(pynest/do_tests.py) + AC_CONFIG_FILES(extras/ConnPlotter/Makefile) EXTRAS_SUBDIRS="$EXTRAS_SUBDIRS ConnPlotter" fi @@ -1047,10 +1078,10 @@ echo "C++ compiler : $CXX" echo "C++ compiler flags : "`echo $AM_CXXFLAGS | sed 's/^[ ]*//g'` echo -if test "$HAVE_PYTHON" = yes; then - echo "Enable PyNEST : Yes (Python: $PYTHON_EXEC)" +if test "x$have_python" = "xyes" ; then + echo "Python bindings : Yes (Python $PYTHON_VERSION: $PYTHON)" else - echo "Enable PyNEST : No" + echo "Python bindings : No" fi if test x`echo $SLI_USER_MODULES | tr -d " "` != x; then @@ -1104,6 +1135,19 @@ else echo "Use MUSIC : No" fi +if test "x$HAVE_LIBNEUROSIM" != xno; then + echo "Use libneurosim : Yes" + if test "x$LIBNEUROSIM_INCLUDE" != x; then + echo " libneurosim inlude: $LIBNEUROSIM_INCLUDE" + fi + if test "x$LIBNEUROSIM_LIBS" != x; then + echo " libneurosim libs : $LIBNEUROSIM_LIBS $LIBNEUROSIM_PY_LIBS" + fi +else + echo "Use libneurosim : No" +fi + + echo echo "--------------------------------------------------------------------------------" echo @@ -1113,12 +1157,10 @@ echo echo "Documentation and examples will be installed to:" echo " ${PKGDOCDIR_AS_CONFIGURED}/" echo -if test "$HAVE_PYTHON" != no; then - if test "$PYNEST_PREFIX" != "NONE"; then +if test "x$have_python" = "xyes"; then echo "PyNEST will be installed to:" - echo " $PYNEST_PREFIX/lib/python$PYTHON_VERSION/site-packages/nest" + printf " "; eval eval echo " ${pyexecdir}" echo - fi fi echo "--------------------------------------------------------------------------------" echo @@ -1180,5 +1222,5 @@ fi echo "If you experience problems with the installation or the use of" echo "NEST, please see http://nest-initiative.org/index.php/FAQ, or" echo "go to http://nest-initiative.org/index.php/Community to find out" -echo "how to join the user mailing list" +echo "how to join the user mailing list." echo diff --git a/conngen/Makefile.am b/conngen/Makefile.am index b5964c478e..035df6b3a8 100644 --- a/conngen/Makefile.am +++ b/conngen/Makefile.am @@ -27,7 +27,7 @@ AM_CPPFLAGS= -I$(top_srcdir)/libnestutil\ -I$(top_srcdir)/sli\ -I$(top_srcdir)/nestkernel\ @INCLTDL@ \ - @GSL_CFLAGS@ @MUSIC_INCLUDE@ @MPI_INCLUDE@ + @GSL_CFLAGS@ @MUSIC_INCLUDE@ @MPI_INCLUDE@ @LIBNEUROSIM_INCLUDE@ nobase_pkgdata_DATA=\ sli/conngen-interface.sli diff --git a/conngen/cg_connect.cpp b/conngen/cg_connect.cpp index 87152c1492..cde204aa11 100644 --- a/conngen/cg_connect.cpp +++ b/conngen/cg_connect.cpp @@ -35,8 +35,16 @@ namespace nest int source, target, num_parameters = cg->arity(); if (num_parameters == 0) { + // connect source to target while (cg->next(source, target, NULL)) - ConnectionGeneratorModule::get_network().connect(source + source_offset, target + target_offset, syn); + { + if (ConnectionGeneratorModule::get_network().is_local_gid(target + target_offset)) + { + Node* const target_node = ConnectionGeneratorModule::get_network().get_node(target + target_offset); + const thread target_thread = target_node->get_thread(); + ConnectionGeneratorModule::get_network().connect(source + source_offset, target + target_offset, target_node, target_thread, syn); + } + } } else if (num_parameters == 2) { @@ -47,8 +55,16 @@ namespace nest long d_idx = (*params_map)[names::delay]; std::vector params(2); + // connect source to target with weight and delay while (cg->next(source, target, ¶ms[0])) - ConnectionGeneratorModule::get_network().connect(source + source_offset, target + target_offset, params[w_idx], params[d_idx], syn); + { + if (ConnectionGeneratorModule::get_network().is_local_gid(target + target_offset)) + { + Node* const target_node = ConnectionGeneratorModule::get_network().get_node(target + target_offset); + const thread target_thread = target_node->get_thread(); + ConnectionGeneratorModule::get_network().connect(source + source_offset, target + target_offset, target_node, target_thread, params[w_idx], params[d_idx], syn); + } + } } else { @@ -65,8 +81,16 @@ namespace nest int source, target, num_parameters = cg->arity(); if (num_parameters == 0) { + // connect source to target while (cg->next(source, target, NULL)) - ConnectionGeneratorModule::get_network().connect(source_gids.at(source), target_gids.at(target), syn); + { + if (ConnectionGeneratorModule::get_network().is_local_gid(target_gids.at(target))) + { + Node* const target_node = ConnectionGeneratorModule::get_network().get_node(target_gids.at(target)); + const thread target_thread = target_node->get_thread(); + ConnectionGeneratorModule::get_network().connect(source_gids.at(source), target_gids.at(target), target_node, target_thread, syn); + } + } } else if (num_parameters == 2) { @@ -77,8 +101,16 @@ namespace nest long d_idx = (*params_map)[names::delay]; std::vector params(2); + // connect source to target with weight and delay while (cg->next(source, target, ¶ms[0])) - ConnectionGeneratorModule::get_network().connect(source_gids.at(source), target_gids.at(target), params[w_idx], params[d_idx], syn); + { + if (ConnectionGeneratorModule::get_network().is_local_gid(target_gids.at(target))) + { + Node* const target_node = ConnectionGeneratorModule::get_network().get_node(target_gids.at(target)); + const thread target_thread = target_node->get_thread(); + ConnectionGeneratorModule::get_network().connect(source_gids.at(source), target_gids.at(target), target_node, target_thread, params[w_idx], params[d_idx], syn); + } + } } else { @@ -87,67 +119,155 @@ namespace nest } } + /** + * Set the masks on the ConnectionGenerator cg. This function also + * creates the masks from the given RangeSets sources and targets. + * + * \param cg The ConnectionGenerator to set the masks on + * \param sources The source ranges to create the source masks from + * \param targets The target ranges to create the target masks from + */ void cg_set_masks(ConnectionGeneratorDatum& cg, RangeSet& sources, RangeSet& targets) { - std::vector masks(Communicator::get_num_processes()); - cg_create_masks(&masks, sources, targets); + long np = Communicator::get_num_processes(); + std::vector masks(np, ConnectionGenerator::Mask(1, np)); + cg_create_masks(&masks, sources, targets); cg->setMask(masks, Communicator::get_rank()); } + /** + * Create the masks for sources and targets based on the contiguous + * ranges given in sources and targets. We need to do some index + * translation here, as the CG expects indices from 0..n for both + * source and target populations, while the RangeSets sources and + * targets contain NEST global indices (gids). + * + * The masks for the sources must contain all nodes (local+remote). + * The skip of the mask was set to 1 in cg_set_masks(). The same + * source mask is stored n_proc times on each process. + * + * The masks for the targets must only contain local nodes. This is + * achieved by first setting skip to num_processes upon creation of + * the mask in cg_set_masks(), and second by the fact that for each + * contiguous range of nodes in a mask, each of them contains the + * index-translated id of the first local neuron as the first + * entry. If this renders the range empty (i.e. because the first + * local id is beyond the last element of the range), the range is + * not added to the mask. + * + * \param masks The std::vector of Masks to populate + * \param sources The source ranges to create the source masks from + * \param targets The target ranges to create the target masks from + * + * \note Each process computes the full set of source and target + * masks, i.e. one mask per rank will be created on each rank. + * + * \note Setting the masks for all processes on each process might + * become a memory bottleneck when going to very large numbers of + * processes. Especially so for the source masks, which are all the + * same. This could be solved by making the ConnectionGenerator + * interface MPI aware and communicating the masks during connection + * setup. + */ void cg_create_masks(std::vector* masks, RangeSet& sources, RangeSet& targets) { - // We need to do some index translation here as the CG expects - // indices from 0..n for both source and target populations. + // The index of the left border of the currently looked at range + // (counting from 0). This is used for index translation. + size_t cg_idx_left = 0; - size_t length = 0; + // For sources, we only need to translate from NEST to CG indices. for (RangeSet::iterator source = sources.begin(); source != sources.end(); ++source) { + size_t num_elements = source->last - source->first; + size_t right = cg_idx_left + num_elements; for (size_t proc = 0; proc < static_cast(Communicator::get_num_processes()); ++proc) - { - size_t last = source->last - source->first; - if (proc <= last) - { - size_t left = proc + length; - size_t right = last + length; - (*masks)[(proc + source->first) % Communicator::get_num_processes()].sources.insert(left, right); - } - } - length += source->last - source->first + 1; + (*masks)[proc].sources.insert(cg_idx_left, right); + cg_idx_left += num_elements + 1; } - length = 0; + // Reset the index of the left border of the range for index + // translation for the targets. + cg_idx_left = 0; + for (RangeSet::iterator target = targets.begin(); target != targets.end(); ++target) { + size_t num_elements = target->last - target->first; for (size_t proc = 0; proc < static_cast(Communicator::get_num_processes()); ++proc) { - size_t last = target->last - target->first; - if (proc <= last) + // Make sure that the range is only added on as many ranks as + // there are elements in the range, or exactly on every rank, + // if there are more elements in the range. + if (proc <= num_elements) { - size_t left = proc + length; - size_t right = last + length; + // For the different ranks, left will take on the CG indices + // of all first local nodes that are contained in the range. + // The rank, where this mask is to be used is determined + // below when inserting the mask. + size_t left = cg_idx_left + proc; + + // right is set to the CG index of the right border of the + // range. This is the same for all ranks. + size_t right = cg_idx_left + num_elements; + + // We index the masks according to the modulo distribution + // of neurons in NEST. This ensures that the mask is set for + // the rank where left acutally is the first neuron fromt + // the currently looked at range. (*masks)[(proc + target->first) % Communicator::get_num_processes()].targets.insert(left, right); } } - length += target->last - target->first + 1; + + // Update the CG index of the left border of the next range to + // be one after the current range. + cg_idx_left += num_elements + 1; } } + /** + * Calculate the right border of the contiguous range of gids + * starting at left. The element is found using a binary search with + * stepsize step. + * + * \param left The leftmost element of the range + * \param step The step size for the binary search + * \param gids The std::vector of gids to search in + */ index cg_get_right_border(index left, size_t step, std::vector& gids) { - if (left == gids.size() -1) + // Check if left is already the index of the last element in + // gids. If yes, return left as the right border + if (left == gids.size() - 1) return left; + // leftmost_r is the leftmost right border during the search long leftmost_r = -1; - long i = gids.size() - 1, last_i = gids.size() -1; - long right = -1; + // Initialize the search index i to the last valid index into gids + // and last_i to i. + long i = gids.size() - 1, last_i = i; + while(true) { - if ((i == static_cast(gids.size()) - 1 && gids[i] - gids[left] == i - static_cast(left)) || i == leftmost_r) + // If i points to the end of gids and the distance between i and + // left is the same as between the values gids[i] and gids[left] + // (i.e. gid[i+1] == gid[i]+1 for all i), or if i is pointing at + // the position of the leftmost right border we found until now + // (i.e. we're back at an already visited index), we found the + // right border of the contiguous range (last_i) and return it. + if ((i == static_cast(gids.size()) - 1 && + gids[i] - gids[left] == i - static_cast(left)) + || i == leftmost_r) return last_i; + // Store the current value of i in last_i. This is the current + // candidate for the right border of the range. last_i = i; + + // If the range between gids[left] and gids[i] is contiguous, + // set i to the right by step steps, else update the variable + // for leftmost_r to the current i (i.e. the known leftmost + // position) and set i to the left by step steps. if (gids[i] - gids[left] == i - static_cast(left)) i += step; else @@ -156,25 +276,45 @@ namespace nest i -= step; } + // Reduce the search interval by half its size if it is > 1. + // This adaptation is the basis of the binary search. if (step != 1) step /= 2; } - return right; + + // The border should always be found and returned during the while + // loop above. This should never be reached. + assert(false && "no right border found during search"); + return 0; } + /** + * Determine all contiguous ranges found in a given vector of gids + * and add the ranges to the given RangeSet. + * + * \param ranges A reference to the RangeSet to add to + * \param gids The std::vector of gids + * + * \note We do not store the indices into the given range, but + * instead we store the actual gids. This allows us to use CG + * generated indices as indices into the ranges spanned by the + * RangeSet. Index translation is done in cg_create_masks(). + */ void cg_get_ranges(RangeSet& ranges, std::vector& gids) { - index right = 0, left = 0; + index right, left = 0; while(true) { + // Determine the right border of the contiguous range starting + // at left. The initial step is set to half the length of the + // interval between left and the end of gids. right = cg_get_right_border(left, (gids.size() - left) / 2, gids); ranges.push_back(Range(gids[left], gids[right])); - if (right == gids.size() - 1) + if (right == gids.size() - 1) // We're at the end of gids and stop break; else - left = right + 1; + left = right + 1; // The new left border is one after the old right } } - } // namespace nest diff --git a/conngen/conngenmodule.cpp b/conngen/conngenmodule.cpp index 938e9e9c60..658e25645d 100644 --- a/conngen/conngenmodule.cpp +++ b/conngen/conngenmodule.cpp @@ -50,15 +50,14 @@ namespace nest ConnectionGeneratorType.deletetypename(); } - const std::string ConnectionGeneratorModule::name(void) const + const std::string ConnectionGeneratorModule::name() const { - return std::string("ConnectionGeneratorModule"); // Return name of the module + return std::string("ConnectionGeneratorModule"); } - const std::string ConnectionGeneratorModule::commandstring(void) const + const std::string ConnectionGeneratorModule::commandstring() const { - return std::string("/conngen /C++ ($Revision: 10104 $) provide-component " - "/conngen-interface /SLI (9843) require-component "); + return std::string("(conngen-interface) run"); } void ConnectionGeneratorModule::init(SLIInterpreter *i) @@ -66,16 +65,50 @@ namespace nest ConnectionGeneratorType.settypename("connectiongeneratortype"); ConnectionGeneratorType.setdefaultaction(SLIInterpreter::datatypefunction); - // Register the connection generator functions as SLI commands. + // Register the user functions of the connection generator interface i->createcommand("CGConnect_cg_i_i_D_l", &cgconnect_cg_i_i_D_lfunction); - i->createcommand("CGConnect_cg_a_a_D_l", &cgconnect_cg_a_a_D_lfunction); - i->createcommand("cgsetmask_cg_a_a", &cgsetmask_cg_a_afunction); - i->createcommand("cgstart", &cgstartfunction); - i->createcommand("cgnext", &cgnextfunction); + i->createcommand("CGConnect_cg_iV_iV_D_l", &cgconnect_cg_iV_iV_D_lfunction); + i->createcommand("CGParse", &cgparse_sfunction); + i->createcommand("CGParseFile", &cgparsefile_sfunction); + i->createcommand("CGSelectImplementation", &cgselectimplementation_s_sfunction); + + // Register the low level functions of the connection generator interface + i->createcommand("cgsetmask_cg_iV_iV", &cgsetmask_cg_iV_iVfunction); + i->createcommand("cgstart", &cgstart_cgfunction); + i->createcommand("cgnext", &cgnext_cgfunction); } + /* BeginDocumentation + Name: CGConnect - Establish connections contained in a ConnectionGenerator + + Synopsis: + cg sources targets -> - + cg sources targets params -> - + cg sources targets syn_model -> - + cg sources targets params syn_model -> - + + Parameters: + cg - ConnectionGenerator + sources - The sources. Either a subnet or a list of nodes + targets - The targets. Either a subnet or a list of nodes + params - A dict specifying the index of /weight and /delay + in the value set of the connection generator + syn_model - A literal specifying te synapse model to be used + + Description: + CGConnect connects a source and a target population according to + the rules defined in the given connection generator. params is an + optional dictionary, that maps the names /weight and/or /delay to + their integer index in the value set in the connection generator. + If not specified, the synapse model is taken from the Options of + the Connect command. + + Author: Jochen Martin Eppler + FirstVersion: August 2012 + SeeAlso: Connect, synapsedict, GetOptions, CGParse, CGParseFile, CGSelectImplementation, cgstart, cgsetmask, cgnext + */ + // Connect for conn_generator subnet subnet dict synapsetype - // See lib/sli/nest-init.sli for details void ConnectionGeneratorModule::CGConnect_cg_i_i_D_lFunction::execute(SLIInterpreter *i) const { i->assert_stack_load(5); @@ -95,7 +128,12 @@ namespace nest if (! sources->is_homogeneous()) { i->message(SLIInterpreter::M_ERROR, "CGConnect_cg_i_i_D_l", "sources must be a homogeneous subnet."); - throw SubnetExpected(); + throw BadProperty(); + } + if (dynamic_cast(*sources->local_begin())) + { + i->message(SLIInterpreter::M_ERROR, "CGConnect_cg_i_i_D_l", "Only 1-dim subnets are supported as sources."); + throw BadProperty(); } Subnet* targets = dynamic_cast(get_network().get_node(target_id)); @@ -107,7 +145,12 @@ namespace nest if (! targets->is_homogeneous()) { i->message(SLIInterpreter::M_ERROR, "CGConnect_cg_i_i_D_l", "targets must be a homogeneous subnet."); - throw SubnetExpected(); + throw BadProperty(); + } + if (dynamic_cast(*targets->local_begin())) + { + i->message(SLIInterpreter::M_ERROR, "CGConnect_cg_i_i_D_l", "Only 1-dim subnets are supported as targets."); + throw BadProperty(); } const Token synmodel = get_network().get_synapsedict().lookup(synmodel_name); @@ -131,10 +174,8 @@ namespace nest i->EStack.pop(); } - // Connect for conn_generator array array dict synapsetype - // See lib/sli/nest-init.sli for details - void ConnectionGeneratorModule::CGConnect_cg_a_a_D_lFunction::execute(SLIInterpreter *i) const + void ConnectionGeneratorModule::CGConnect_cg_iV_iV_D_lFunction::execute(SLIInterpreter *i) const { i->assert_stack_load(5); @@ -162,7 +203,125 @@ namespace nest } - void ConnectionGeneratorModule::CGSetMask_cg_a_aFunction::execute(SLIInterpreter *i) const + /* BeginDocumentation + Name: CGParse - Call ConnectionGenerator::fromXML() and return a ConnectionGenerator + + Synopsis: + xml_string CGParse -> cg + + Parameters: + xml_string - The XML string to parse. + + Description: + Return a ConnectionGenerator created by deserializing the given + XML string. The library to parse the XML string can be selected using + CGSelectImplementation + + Author: Jochen Martin Eppler + FirstVersion: September 2013 + SeeAlso: CGParseFile, CGConnect, CGSelectImplementation, cgstart, cgsetmask, cgnext + */ + void ConnectionGeneratorModule::CGParse_sFunction::execute(SLIInterpreter *i) const + { + i->assert_stack_load(1); + + StringDatum xml = getValue(i->OStack.pick(0)); + ConnectionGeneratorDatum cgd = ConnectionGenerator::fromXML(xml); + + i->OStack.pop(1); + i->OStack.push(cgd); + i->EStack.pop(); + } + + + /* BeginDocumentation + Name: CGParseFile - Call ConnectionGenerator::fromXMLFile() and return a ConnectionGenerator + + Synopsis: + xml_filename CGParseFile -> cg + + Parameters: + xml_filename - The XML file to read. + + Description: + Return a ConnectionGenerator created by deserializing the given + XML file. The library to parse the XML file can be selected using + CGSelectImplementation + + Author: Jochen Martin Eppler + FirstVersion: February 2014 + SeeAlso: CGParse, CGConnect, CGSelectImplementation, cgstart, cgsetmask, cgnext + */ + void ConnectionGeneratorModule::CGParseFile_sFunction::execute(SLIInterpreter *i) const + { + i->assert_stack_load(1); + + StringDatum xml = getValue(i->OStack.pick(0)); + ConnectionGeneratorDatum cgd = ConnectionGenerator::fromXMLFile(xml); + + i->OStack.pop(1); + i->OStack.push(cgd); + i->EStack.pop(); + } + + + /* BeginDocumentation + Name: CGSelectImplementation - Call ConnectionGenerator::selectCGImplementation() + + Synopsis: + tag library CGParse -> - + + Parameters: + tag - The XML tag to associate with a library. + library - The library to provide the parsing for CGParse + + Description: + Select a library to provide a parser for XML files and associate + an XML tag with the library. + + Author: Jochen Martin Eppler + FirstVersion: September 2013 + SeeAlso: CGParse, CGParseFile, CGConnect, cgstart, cgsetmask, cgnext + */ + void ConnectionGeneratorModule::CGSelectImplementation_s_sFunction::execute(SLIInterpreter *i) const + { + i->assert_stack_load(2); + + StringDatum library = getValue(i->OStack.pick(0)); + StringDatum tag = getValue(i->OStack.pick(1)); + ConnectionGenerator::selectCGImplementation(tag, library); + + i->OStack.pop(1); + i->EStack.pop(); + } + + + /* BeginDocumentation + Name: cgsetmask - Call setMasks() on a ConnectionGenerator + + Synopsis: + cg sources targets cgsetmask -> - + + Parameters: + cg - ConnectionGenerator + sources - A list of nodes used as source masks + targets - A list of nodes used as target masks + + Description: + Set masks for sources and targets on a given ConnectionGenerator + cg. This is calling the setMasks() function on cg internally. + + Remarks: + This function is part of the low-level access API for the + ConnectionGenerator module. It is mainly used for debugging + purposes. Usually, connections are created from a + ConnectionGenerator using CGConnect. + + Author: Mikael Djurfeldt + FirstVersion: March 2011 + SeeAlso: CGParse, CGParseFile, CGConnect, CGSelectImplementation, cgstart, cgnext + */ + void ConnectionGeneratorModule::CGSetMask_cg_iV_iVFunction::execute(SLIInterpreter *i) const { i->assert_stack_load(3); @@ -184,7 +343,7 @@ namespace nest /* BeginDocumentation - Name: CGStartFunction - Call start() on a ConnectionGenerator + Name: cgstart - Call start() on a ConnectionGenerator Synopsis: cg cgstart -> - @@ -192,18 +351,26 @@ namespace nest Parameters: cg - ConnectionGenerator + Description: + Call the start() function on a given ConnectionGenerator cg. + + Remarks: + This function is part of the low-level access API for the + ConnectionGenerator module. It is mainly used for debugging + purposes. Usually, connections are created from a + ConnectionGenerator using CGConnect. + Author: Mikael Djurfeldt FirstVersion: March 2011 - Availability: - SeeAlso: CGNextFunction + SeeAlso: CGParse, CGParseFile, CGConnect, CGSelectImplementation, cgsetmask, cgnext */ - void ConnectionGeneratorModule::CGStartFunction::execute(SLIInterpreter *i) const + void ConnectionGeneratorModule::CGStart_cgFunction::execute(SLIInterpreter *i) const { i->assert_stack_load(1); ConnectionGeneratorDatum cgd = getValue(i->OStack.pick(0)); - cgd->start (); + cgd->start(); i->OStack.pop(1); i->EStack.pop(); @@ -211,7 +378,7 @@ namespace nest /* BeginDocumentation - Name: CGNextFunction - Call next() on a ConnectionGenerator + Name: cgnext - Call next() on a ConnectionGenerator Synopsis: cg cgnext -> source target v[0] ... true | false @@ -219,36 +386,48 @@ namespace nest Parameters: cg - ConnectionGenerator + Description: + Call the next() function on a given ConnectionGenerator cg + to iterate cg's connections on the SLI level. This function + will return the source and the target of the connection, a + list containing the values for the connection (if there are + any), and true, or false, if cg cannot be iterated further. + + Remarks: + This function is part of the low-level access API for the + ConnectionGenerator module. It is mainly used for debugging + purposes. Usually, connections are created from a + ConnectionGenerator using CGConnect. + Author: Mikael Djurfeldt FirstVersion: December 2012 - Availability: - SeeAlso: CGStartFunction + SeeAlso: CGParse, CGParseFile, CGConnect, CGSelectImplementation, cgstart, cgsetmask */ - void ConnectionGeneratorModule::CGNextFunction::execute(SLIInterpreter *i) const + void ConnectionGeneratorModule::CGNext_cgFunction::execute(SLIInterpreter *i) const { i->assert_stack_load(1); ConnectionGeneratorDatum cgd = getValue(i->OStack.pick(0)); - ConnectionGenerator* generator = cgd.get (); + ConnectionGenerator* generator = cgd.get(); int j, k; - int arity = generator->arity (); + int arity = generator->arity(); double* values = new double[arity]; i->OStack.pop(1); i->EStack.pop(); - if (generator->next (j, k, values)) + if (generator->next(j, k, values)) { - i->OStack.push (j); - i->OStack.push (k); + i->OStack.push(j); + i->OStack.push(k); for (int m = 0; m < arity; ++m) - i->OStack.push (values[m]); + i->OStack.push(values[m]); delete[] values; - i->OStack.push (true); + i->OStack.push(true); } else - i->OStack.push (false); + i->OStack.push(false); - cgd.unlock (); + cgd.unlock(); } diff --git a/conngen/conngenmodule.h b/conngen/conngenmodule.h index ed4262fabb..46479542c4 100644 --- a/conngen/conngenmodule.h +++ b/conngen/conngenmodule.h @@ -28,7 +28,8 @@ #include "modelrange.h" -#include "connection_generator.h" +#include + typedef std::vector RangeSet; typedef ConnectionGenerator::ClosedInterval Range; @@ -53,45 +54,50 @@ namespace nest */ void init(SLIInterpreter*); - const std::string name(void) const; - const std::string commandstring(void) const; - - /* - * SLI functions: See source file for documentation - */ + const std::string name() const; + const std::string commandstring() const; class CGConnect_cg_i_i_D_lFunction : public SLIFunction { - public: - void execute(SLIInterpreter *) const; + void execute(SLIInterpreter*) const; } cgconnect_cg_i_i_D_lfunction; - class CGConnect_cg_a_a_D_lFunction : public SLIFunction + class CGConnect_cg_iV_iV_D_lFunction : public SLIFunction { - public: - void execute(SLIInterpreter *) const; - } cgconnect_cg_a_a_D_lfunction; + void execute(SLIInterpreter*) const; + } cgconnect_cg_iV_iV_D_lfunction; - class CGSetMask_cg_a_aFunction : public SLIFunction + class CGParse_sFunction: public SLIFunction { - public: - void execute(SLIInterpreter *) const; - } cgsetmask_cg_a_afunction; + void execute(SLIInterpreter*) const; + } cgparse_sfunction; - class CGStartFunction : public SLIFunction + class CGParseFile_sFunction: public SLIFunction { - void execute(SLIInterpreter *) const; - } cgstartfunction; + void execute(SLIInterpreter*) const; + } cgparsefile_sfunction; - class CGNextFunction : public SLIFunction + class CGSelectImplementation_s_sFunction: public SLIFunction { - void execute(SLIInterpreter *) const; - } cgnextfunction; + void execute(SLIInterpreter*) const; + } cgselectimplementation_s_sfunction; - /** - * Return a reference to the network managed by the topology module. - */ - static Network &get_network(); + class CGSetMask_cg_iV_iVFunction : public SLIFunction + { + void execute(SLIInterpreter*) const; + } cgsetmask_cg_iV_iVfunction; + + class CGStart_cgFunction: public SLIFunction + { + void execute(SLIInterpreter*) const; + } cgstart_cgfunction; + + class CGNext_cgFunction: public SLIFunction + { + void execute(SLIInterpreter*) const; + } cgnext_cgfunction; + + static Network& get_network(); private: diff --git a/conngen/sli/conngen-interface.sli b/conngen/sli/conngen-interface.sli index 1d783410b3..52f223883e 100644 --- a/conngen/sli/conngen-interface.sli +++ b/conngen/sli/conngen-interface.sli @@ -20,11 +20,66 @@ * */ -/conngen-interface /SLI ($Revision: 9843 $) provide-component +/CGConnect_cg_i_i_l { + << >> exch + CGConnect_cg_i_i_D_l +} def -/CGConnect trie +/CGConnect_cg_iV_iV_l { + << >> exch + CGConnect_cg_iV_iV_D_l +} def + +/CGConnect_cg_a_a_D_l { + 4 3 roll % stack: cg trg param syntype src + cv_iv % convert src to intvectortype + 4 -3 roll % stack: cg src trg param syntype + 3 2 roll % stack: cg trg param syntype src + cv_iv % convert trg to intvectortype + 3 -2 roll % stack: cg src trg param syntype + CGConnect_cg_iV_iV_D_l +} def + +/CGConnect_cg_a_a_l { + << >> exch + CGConnect_cg_a_a_D_l +} def + +/CGConnect_main trie [/connectiongeneratortype /integertype /integertype /dictionarytype /literaltype] /CGConnect_cg_i_i_D_l load addtotrie + [/connectiongeneratortype /integertype /integertype /literaltype] + /CGConnect_cg_i_i_l load addtotrie + [/connectiongeneratortype /intvectortype /intvectortype /dictionarytype /literaltype] + /CGConnect_cg_iV_iV_D_l load addtotrie + [/connectiongeneratortype /intvectortype /intvectortype /literaltype] + /CGConnect_cg_iV_iV_l load addtotrie [/connectiongeneratortype /arraytype /arraytype /dictionarytype /literaltype] /CGConnect_cg_a_a_D_l load addtotrie + [/connectiongeneratortype /arraytype /arraytype /literaltype] + /CGConnect_cg_a_a_l load addtotrie +def + +/CGConnect [/literaltype] { + CGConnect_main +} def + +/CGConnect [/anytype] { + /Connect /synapse_model GetOption + CGConnect_main +} def + +% --------------------------- + +/cgsetmask_cg_a_a { + cv_iv % convert target to intvectortype + exch cv_iv exch % convert source to intvectortype + cgsetmask_cg_iV_iV +} def + +/cgsetmask trie + [/connectiongeneratortype /intvectortype /intvectortype] + /cgsetmask_cg_iV_iV load addtotrie + [/connectiongeneratortype /arraytype /arraytype] + /cgsetmask_cg_a_a load addtotrie def diff --git a/doc/copyright_header.txt b/doc/copyright_header.cpp similarity index 97% rename from doc/copyright_header.txt rename to doc/copyright_header.cpp index e33e95c4c7..c6058f0ba4 100644 --- a/doc/copyright_header.txt +++ b/doc/copyright_header.cpp @@ -1,5 +1,5 @@ /* - * name the file + * {{file_name}} * * This file is part of NEST. * diff --git a/doc/copyright_header.py b/doc/copyright_header.py new file mode 100644 index 0000000000..ecf4bd3a99 --- /dev/null +++ b/doc/copyright_header.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# +# {{file_name}} +# +# This file is part of NEST. +# +# Copyright (C) 2004 The NEST Initiative +# +# NEST 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 2 of the License, or +# (at your option) any later version. +# +# NEST 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 NEST. If not, see . diff --git a/doc/fulldoc.conf b/doc/fulldoc.conf index 658207ae83..05e220c80d 100644 --- a/doc/fulldoc.conf +++ b/doc/fulldoc.conf @@ -66,7 +66,8 @@ INPUT = $(TOPSRCDIR)/nest \ $(TOPSRCDIR)/testsuite \ $(TOPSRCDIR)/models \ $(TOPSRCDIR)/precise \ - $(TOPSRCDIR)/topology + $(TOPSRCDIR)/topology \ + $(TOPSRCDIR)/conngen FILE_PATTERNS = *.c \ *.cpp \ *.cc \ diff --git a/doc/normaldoc.conf b/doc/normaldoc.conf index 9640afb3b7..09c865c028 100644 --- a/doc/normaldoc.conf +++ b/doc/normaldoc.conf @@ -66,7 +66,8 @@ INPUT = $(TOPSRCDIR)/nest \ $(TOPSRCDIR)/testsuite \ $(TOPSRCDIR)/models \ $(TOPSRCDIR)/precise \ - $(TOPSRCDIR)/topology + $(TOPSRCDIR)/topology \ + $(TOPSRCDIR)/conngen FILE_PATTERNS = *.c \ *.cpp \ *.cc \ diff --git a/doc/quickref.html b/doc/quickref.html index 3e9c28c92b..16bfca52a8 100644 --- a/doc/quickref.html +++ b/doc/quickref.html @@ -759,10 +759,6 @@

Setting and retrieving parameters of network elements

type Return the type of an element. - - FindNodes - Find all nodes with a certain property. - ResetKernel Put the simulation kernel back to its initial state. @@ -1257,7 +1253,7 @@

Random deviate generator types

Poisson random deviate generator. - uniformint + uniform_int Uniform integer random deviate generator. @@ -3307,78 +3303,6 @@

Startup and initialization

welcome Print SLI welcome message. - - stdlibrevision - Revision number of sli-init libray. - - - - -

Version control

- -

Operations with version numbers, strings and arrays

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
s2vConvert version number string to array.
v2sConvert version number array to string.
validateAssure correct format of version number array.
vcmpCompare two version number arrays.
veqAre two version number arrays equal?
vgeq"Greater or equal" for version number arrays.
vgt"Greater than" for version number arrays.
vleq"Less or equal" for version number arrays.
vlt"Less than" for version number arrays.
- -

Library version control

- - - - - - - - - - - - - - - - - - -
provideState that code provides (the SLI part of) a library.
provide-componentState that code provides a subcomponent of a library.
requireState that code requires a certain library.
require-componentState that code requires a certain subcomponent of a library.
diff --git a/examples/MyModule/Makefile.am b/examples/MyModule/Makefile.am index 7f8d259db2..05735f2f00 100644 --- a/examples/MyModule/Makefile.am +++ b/examples/MyModule/Makefile.am @@ -43,7 +43,7 @@ AM_CPPFLAGS= @NEST_CPPFLAGS@ \ pkgdatadir=@datadir@/nest nobase_pkgdata_DATA=\ - sli/mymodule.sli + sli/mymodule-init.sli install-slidoc: NESTRCFILENAME=/dev/null $(DESTDIR)$(NEST_PREFIX)/bin/sli --userargs="@HELPDIRS@" $(NEST_PREFIX)/share/nest/sli/install-help.sli diff --git a/examples/MyModule/drop_odd_spike_connection.h b/examples/MyModule/drop_odd_spike_connection.h index 3fdec53275..3fe06a2160 100644 --- a/examples/MyModule/drop_odd_spike_connection.h +++ b/examples/MyModule/drop_odd_spike_connection.h @@ -1,6 +1,3 @@ -#ifndef DROP_ODD_SPIKE_CONNECTION_H -#define DROP_ODD_SPIKE_CONNECTION_H - /* * drop_odd_spike_connection.h * @@ -23,6 +20,9 @@ * */ +#ifndef DROP_ODD_SPIKE_CONNECTION_H +#define DROP_ODD_SPIKE_CONNECTION_H + #include "connection_het_wd.h" /* BeginDocumentation diff --git a/examples/MyModule/mymodule.cpp b/examples/MyModule/mymodule.cpp index fca3ed5f4f..964b62ff65 100644 --- a/examples/MyModule/mymodule.cpp +++ b/examples/MyModule/mymodule.cpp @@ -66,8 +66,7 @@ mynest::MyModule::MyModule() } mynest::MyModule::~MyModule() - { - } + {} const std::string mynest::MyModule::name(void) const { @@ -76,16 +75,8 @@ mynest::MyModule::~MyModule() const std::string mynest::MyModule::commandstring(void) const { - /* 1. Tell interpreter that we provide the C++ part of MyModule with the - current revision number. - 2. Instruct the interpreter to check that mymodule-init.sli exists, - provides at least version 1.0 of the SLI interface to MyModule, and - to load it. - */ - return std::string( - "/mymodule /C++ ($Revision: 10071 $) provide-component " - "/mymodule /SLI (7165) require-component" - ); + // Instruct the interpreter to load mymodule-init.sli + return std::string("(mymodule-init) run"); } /* BeginDocumentation diff --git a/examples/MyModule/pif_psc_alpha.h b/examples/MyModule/pif_psc_alpha.h index de1e81d6a5..bf69a5446c 100644 --- a/examples/MyModule/pif_psc_alpha.h +++ b/examples/MyModule/pif_psc_alpha.h @@ -1,6 +1,3 @@ -#ifndef PIF_PSC_ALPHA_H -#define PIF_PSC_ALPHA_H - /* * pif_psc_alpha.h * @@ -23,6 +20,8 @@ * */ +#ifndef PIF_PSC_ALPHA_H +#define PIF_PSC_ALPHA_H #include "nest.h" #include "event.h" diff --git a/examples/MyModule/sli/mymodule.sli b/examples/MyModule/sli/mymodule-init.sli similarity index 90% rename from examples/MyModule/sli/mymodule.sli rename to examples/MyModule/sli/mymodule-init.sli index d4646e4e45..8c83c66edf 100644 --- a/examples/MyModule/sli/mymodule.sli +++ b/examples/MyModule/sli/mymodule-init.sli @@ -1,5 +1,5 @@ /* - * mymodule.sli + * mymodule-init.sli * * This file is part of NEST. * @@ -19,6 +19,7 @@ * along with NEST. If not, see . * */ + /* * Initialization file for MyModule. * Run automatically when MyModule is loaded. @@ -26,9 +27,6 @@ M_DEBUG (mymodule.sli) (Initializing SLI support for MyModule.) message -/mymodule /SLI ($Revision: 9952 $) provide-component -/mymodule /C++ (7165) require-component - /StepPatternConnect [ /arraytype /integertype /arraytype /integertype /literaltype ] { StepPatternConnect_Vi_i_Vi_i_l diff --git a/examples/nest/ArtificialSynchrony.sli b/examples/nest/ArtificialSynchrony.sli index c0b0d80dce..d17f748de7 100644 --- a/examples/nest/ArtificialSynchrony.sli +++ b/examples/nest/ArtificialSynchrony.sli @@ -152,7 +152,7 @@ modeldict begin %set resolution and limits on delays % limits must be set BEFORE connecting any elements - [0] + 0 << /resolution h % time steps in ms /off_grid_spiking true % precise neuron model @@ -162,7 +162,7 @@ modeldict begin sim 1 eq { /iaf_psc_alpha_canon nr Create pop } { /iaf_psc_alpha nr Create pop } ifelse - /neurons [0] GetNodes def + /neurons 0 GetGlobalNodes def % connect neurons all to all neurons { diff --git a/examples/nest/Brette_et_al_2007/benchmark.sli b/examples/nest/Brette_et_al_2007/benchmark.sli index 75be70c66f..8dc8d2ce87 100644 --- a/examples/nest/Brette_et_al_2007/benchmark.sli +++ b/examples/nest/Brette_et_al_2007/benchmark.sli @@ -1,22 +1,24 @@ /* - benchmark.sli - - Copyright (C) 2004 The NEST Initiative - This file 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 2 of the License, or - (at your option) any later version. - - This file 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, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ + * benchmark.sli + * + * This file is part of NEST. + * + * Copyright (C) 2004 The NEST Initiative + * + * NEST 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 2 of the License, or + * (at your option) any later version. + * + * NEST 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 NEST. If not, see . + * + */ /* Simulator review diff --git a/examples/nest/Brette_et_al_2007/coba.sli b/examples/nest/Brette_et_al_2007/coba.sli index 00bfe7d2eb..e074e7370a 100644 --- a/examples/nest/Brette_et_al_2007/coba.sli +++ b/examples/nest/Brette_et_al_2007/coba.sli @@ -1,22 +1,24 @@ /* - coba.sli - - Copyright (C) 2004 The NEST Initiative - This file 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 2 of the License, or - (at your option) any later version. - - This file 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, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ + * coba.sli + * + * This file is part of NEST. + * + * Copyright (C) 2004 The NEST Initiative + * + * NEST 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 2 of the License, or + * (at your option) any later version. + * + * NEST 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 NEST. If not, see . + * + */ /* Benchmark 1 of the simulator review diff --git a/examples/nest/Brette_et_al_2007/cuba.sli b/examples/nest/Brette_et_al_2007/cuba.sli index fc49c94655..1e45225ad9 100644 --- a/examples/nest/Brette_et_al_2007/cuba.sli +++ b/examples/nest/Brette_et_al_2007/cuba.sli @@ -1,22 +1,24 @@ /* - cuba.sli - - Copyright (C) 2004 The NEST Initiative - This file 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 2 of the License, or - (at your option) any later version. - - This file 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, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ + * cuba.sli + * + * This file is part of NEST. + * + * Copyright (C) 2004 The NEST Initiative + * + * NEST 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 2 of the License, or + * (at your option) any later version. + * + * NEST 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 NEST. If not, see . + * + */ /* Benchmark 2 of the simulator review diff --git a/examples/nest/Brette_et_al_2007/cuba_ps.sli b/examples/nest/Brette_et_al_2007/cuba_ps.sli index fe3b92d839..fbc34c641f 100644 --- a/examples/nest/Brette_et_al_2007/cuba_ps.sli +++ b/examples/nest/Brette_et_al_2007/cuba_ps.sli @@ -1,22 +1,24 @@ /* - cuba_ps.sli - - Copyright (C) 2004 The NEST Initiative - This file 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 2 of the License, or - (at your option) any later version. - - This file 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, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ + * cuba_ps.sli + * + * This file is part of NEST. + * + * Copyright (C) 2004 The NEST Initiative + * + * NEST 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 2 of the License, or + * (at your option) any later version. + * + * NEST 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 NEST. If not, see . + * + */ /* Benchmark 4 of the simulator review diff --git a/examples/nest/Brette_et_al_2007/cuba_stdp.sli b/examples/nest/Brette_et_al_2007/cuba_stdp.sli index 199b4b9fca..8fdf50c29b 100644 --- a/examples/nest/Brette_et_al_2007/cuba_stdp.sli +++ b/examples/nest/Brette_et_al_2007/cuba_stdp.sli @@ -1,22 +1,24 @@ /* - cuba_stdp.sli - - Copyright (C) 2004 The NEST Initiative - This file 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 2 of the License, or - (at your option) any later version. - - This file 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, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ + * cuba_stdp.sli + * + * This file is part of NEST. + * + * Copyright (C) 2004 The NEST Initiative + * + * NEST 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 2 of the License, or + * (at your option) any later version. + * + * NEST 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 NEST. If not, see . + * + */ /* The fifth simulator review benchmark is implemented as a variation of the @@ -148,12 +150,12 @@ stdp_params rngdict /knuthlfg get 238 CreateRNG /myrng Set % normal distribution to draw several quantities from -myrng rdevdict /normal_clipped_right get CreateRDV /normal_dv Set +myrng rdevdict /normal_clipped get CreateRDV /normal_dv Set normal_dv << /mu mean_potential - /std sigma_potential - /max model_params /V_th get + /sigma sigma_potential + /high model_params /V_th get >> SetStatus diff --git a/examples/nest/Brette_et_al_2007/hh_coba.sli b/examples/nest/Brette_et_al_2007/hh_coba.sli index 2d0e3827d1..63aca755d0 100644 --- a/examples/nest/Brette_et_al_2007/hh_coba.sli +++ b/examples/nest/Brette_et_al_2007/hh_coba.sli @@ -1,22 +1,24 @@ /* - hh_coba.sli - - Copyright (C) 2004 The NEST Initiative - This file 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 2 of the License, or - (at your option) any later version. - - This file 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, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ + * hh_coba.sli + * + * This file is part of NEST. + * + * Copyright (C) 2004 The NEST Initiative + * + * NEST 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 2 of the License, or + * (at your option) any later version. + * + * NEST 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 NEST. If not, see . + * + */ /* Benchmark 3 of the simulator review diff --git a/examples/nest/BrodyHopfield.sli b/examples/nest/BrodyHopfield.sli index 1a2bf6b6cd..52515dec0a 100644 --- a/examples/nest/BrodyHopfield.sli +++ b/examples/nest/BrodyHopfield.sli @@ -56,8 +56,8 @@ ResetKernel net ChangeSubnet model N Create ; -[0] ChangeSubnet -net GetNodes /neurons Set +0 ChangeSubnet +net GetGlobalNodes /neurons Set sd << /to_file true /withgid true >> SetStatus diff --git a/examples/nest/Makefile.am b/examples/nest/Makefile.am index 9f2a49a9d7..4f2bb9ab97 100644 --- a/examples/nest/Makefile.am +++ b/examples/nest/Makefile.am @@ -12,8 +12,28 @@ nobase_data_DATA=\ Brette_et_al_2007/cuba_ps.sli\ Brette_et_al_2007/hh_coba.sli\ Brette_et_al_2007/benchmark.sli\ - HillTononi/ht_current.py\ - HillTononi/ht_poisson.py\ - multimeter.sli - + multimeter.sli\ + music/clocktest.music\ + music/conttest.music\ + music/conttest.py\ + music/eventtest.music\ + music/messages0.dat\ + music/messages1.dat\ + music/minimalmusicsetup.music\ + music/minimalmusicsetup-pynest.music\ + music/minimalmusicsetup_receivenest.py\ + music/minimalmusicsetup_receivenest.sli\ + music/minimalmusicsetup_sendnest.py\ + music/minimalmusicsetup_sendnest.sli\ + music/msgtest.music\ + music/msgtest.py\ + music/spike_exporter.sli\ + music/three_neurons_threaded.music\ + music/three_neurons_threaded_receivenest.sli\ + music/three_neurons_threaded_sendnest.sli +install-data-hook: + chmod 755 $(DESTDIR)@PKGDOCDIR@/examples/music/conttest.py + chmod 755 $(DESTDIR)@PKGDOCDIR@/examples/music/minimalmusicsetup_receivenest.py + chmod 755 $(DESTDIR)@PKGDOCDIR@/examples/music/minimalmusicsetup_sendnest.py + chmod 755 $(DESTDIR)@PKGDOCDIR@/examples/music/msgtest.py diff --git a/examples/nest/Potjans_2014/README.txt b/examples/nest/Potjans_2014/README.txt new file mode 100644 index 0000000000..b6f10867da --- /dev/null +++ b/examples/nest/Potjans_2014/README.txt @@ -0,0 +1,131 @@ +/* + * README.txt + * + * This file is part of NEST. + * + * Copyright (C) 2004 The NEST Initiative + * + * NEST 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 2 of the License, or + * (at your option) any later version. + * + * NEST 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 NEST. If not, see . + * + */ + +Cortical microcircuit simulation: SLI version + +This is an implementation of the multi-layer microcircuit model of early +sensory cortex published by Potjans and Diesmann (2012) The cell-type specific +cortical microcircuit: relating structure and activity in a full-scale spiking +network model. Cereb Cortex, online first. + + +Files: + - network_params.sli + Script containing model parameters + + - sim_params.sli + Script containing simulation and recording parameters + + - user_params.sli + Script containing parameters related to the user system + + - microcircuit.sli + Simulation script + + - run_microcircuit.sh + Bash script. Creates sim_script.sh and submits it to the queue + + - spike_analysis_www.py + Python script for basic analysis + +The bash script is designed for a cluster with a queuing system that uses qsub. +It takes all parameters from user_params.sli and sim_params.sli and can be left +unchanged. The actual simulation script 'microcircuit.sli' does not need to be +changed either. + + +Instructions: + +1. Download NEST (http://www.nest-initiative.org/index.php/Software:Download) + +2. Compile NEST with MPI support (use the --with-mpi option when configuring) + according to the instructions on + http://www.nest-initiative.org/index.php/Software:Installation + +3. In user_params.sli adjust output_dir, mpi_path, and nest_path to your system + +4. In sim_params.sli adjust the following parameters: + + - the number of compute nodes 'n_nodes' + - the number of processors per node 'n_procs_per_node' + - queuing system parameters 'walltime' and 'memory' + - simulation time 't_sim' + + and choose recordables: cortical spikes, thalamic spikes, voltages + +5. In network_params.sli: + + - Choose the network 'area', which scales the numbers of neurons + - When down-scaling: Choose whether full-scale in-degrees should be used. + Setting 'preserve_K' to true preserves most of the dynamics of the + full-size network, as long as 'area' is not too small + - Choose the external input: Poissonian noise 'bg_rate' and/or DC current + 'dc_amplitude' + - Set any thalamic inputs parameters + +6. Run the simulation by typing ./run_microcircuit.sh in your terminal + (microcircuit.sli and the parameter files need to be in the same folder) + +7. Output files and basic analysis: + + - Spikes are written to .gdf files containing GIDs of the recorded neurons + and corresponding spike times in ms. The GIDs are unordered. + Separate files are written out for each population and virtual process. + File names are formed as spike detector label + layer index + population + index + spike detector GID + virtual process + .gdf + - population_GIDs.dat contains the first and last global ID (GID) of the + neurons in each population in the order 2/3e, 2/3i, 4e, 4i, 5e, 5i, 6e, 6i + - Voltages are written to .dat files containing GIDs, times in ms, and the + corresponding membrane potentials in mV. File names are formed as + voltmeter label + layer index + population index + spike detector GID + + virtual process + .dat + + - Run 'spike_analysis.py' with the variable 'datapath' set to the output + folder in order to merge the spike files of each population (including + thalamic ones, if present), sort GIDs, and produce dot plots and firing + rate plots. + - The analysis script does not currently cover voltages. + +The simulation was successfully tested with MPI 1.4.3. +The analysis script works with Python 2.6.6 including packages numpy 1.3.0, +matplotlib 0.99.1.1, and glob. + +--------------------------------------------------- + +Simulation on a single process: + +1. After compiling NEST (not necessarily with MPI), go to the folder that + includes microcircuit.sli and the parameter files and type 'nest' in your + terminal. + +2. Adjust 'area' and 'preserve_K' in network_params.sli such that the network + is small enough to fit on your system. + +3. Ensure that the output directory exists, as it is not created via the bash + script anymore + +4. Type '(microcircuit) run' to start the simulation on a single process. + +A downscaled version ('area' = 0.1) of the network was tested on a single +process with 'preserve_K' = false. However, note that this produces different +network dynamics than the full-scale model. + diff --git a/examples/nest/Potjans_2014/microcircuit.sli b/examples/nest/Potjans_2014/microcircuit.sli new file mode 100644 index 0000000000..a355e793cb --- /dev/null +++ b/examples/nest/Potjans_2014/microcircuit.sli @@ -0,0 +1,615 @@ +/* + * microcircuit.sli + * + * This file is part of NEST. + * + * Copyright (C) 2004 The NEST Initiative + * + * NEST 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 2 of the License, or + * (at your option) any later version. + * + * NEST 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 NEST. If not, see . + * + */ + +/* + Implementation of the multi-layered local cortical network model by + + Potjans, Tobias C., and Markus Diesmann. "The cell-type specific + cortical microcircuit: relating structure and activity in a full-scale + spiking network model." Cerebral Cortex (2014): bhs358. + + Uses user_params.sli, sim_params.sli, and network_params.sli + + function definitions: + - CheckParameters + - PrepareSimulation + - DerivedParameters + - CreateNetworkNodes + - WriteGIDstoFile + - ConnectNetworkNodes + + Tobias Potjans 2008; adapted by Tom Tetzlaff, David Dahmen, + Sacha van Albada 2013; Hannah Bos 2014 +*/ + +/CheckParameters +{ + % non-exhaustive check of parameter dimensions and values + + neuron_model /iaf_psc_exp eq not + { + Rank 0 eq + { + M_WARNING (CheckParameters) + (Unexpected neuron type: script is tuned to /iaf_psc_exp neurons.) + message % this is written to the output file + } if + } if + + % number of layers + /num_layers full_scale_num_neurons length def + % number of populations in each layer + /num_pops_per_layer full_scale_num_neurons Dimensions 1 get def + + conn_probs Dimensions 0 get + num_layers num_pops_per_layer mul + eq not + conn_probs Dimensions 1 get + num_layers num_pops_per_layer mul + eq not or + { + /CheckParameters /conn_probs_dimensions raiseerror + } if + + record_fraction_neurons_spikes + { + frac_rec_spikes 1 gt + { + /CheckParameters /frac_rec_spikes raiseerror + } if + }{ + n_rec_spikes full_scale_num_neurons { Min } Map Min area mul gt + { + /CheckParameters /n_rec_spikes raiseerror + } if + } ifelse + + record_fraction_neurons_voltage + { + frac_rec_voltage 1 gt + { + /CheckParameters /frac_rec_voltage raiseerror + } if + }{ + n_rec_voltage full_scale_num_neurons { Min } Map Min area mul gt + { + /CheckParameters /n_rec_voltage raiseerror + } if + } ifelse + +} def + + + +/PrepareSimulation +{ + ResetKernel + + % set global kernel parameters + 0 + << + /resolution dt + /total_num_virtual_procs n_vp + /communicate_allgather allgather + /overwrite_files overwrite_existing_files + /rng_seeds master_seed [0 n_vp 1 sub] add Range % local RNG seeds + /grng_seed master_seed n_vp add % global RNG seed + /data_path output_path + >> SetStatus + + /seed_offset master_seed n_vp add def + /script_rngs [ n_vp ] + { seed_offset add rngdict /gsl_mt19937 get exch CreateRNG } Table def + /normal_rdvs script_rngs { rdevdict /normal get CreateRDV } Map def + +} def + + +/DerivedParameters +{ + % compute numbers of neurons for the given surface area + /num_neurons + full_scale_num_neurons { area mul cvi } [2] Map + def + + % compute PSC amplitude from PSP amplitude + + model_params using + % factor for transforming PSP amplitude to PSC amplitude + + /re tau_m tau_syn_ex div def + /de tau_syn_ex tau_m sub def + /ri tau_m tau_syn_in div def + /di tau_syn_in tau_m sub def + + /PSC_e_over_PSP_e + (((C_m)^(-1)*tau_m*tau_syn_ex/de*(re^(tau_m/de)-re^(tau_syn_ex/de)))^(-1)) + ExecMath def + + /PSC_i_over_PSP_i + (((C_m)^(-1)*tau_m*tau_syn_in/di*(ri^(tau_m/di)-ri^(tau_syn_in/di)))^(-1)) + ExecMath def + endusing + + /PSC_e PSC_e_over_PSP_e PSP_e mul def + /PSC_e_23_4 PSC_e_over_PSP_e PSP_e_23_4 mul def + /PSP_i PSP_e g mul def + /PSC_i PSC_i_over_PSP_i PSP_i mul def + + % PSC amplitude for all external input + /PSC_ext PSC_e_over_PSP_e PSP_ext mul def + + % array of synaptic current amplitudes + [4 2 4] [PSC_e PSC_i] LayoutArray /PSC_array Set + PSC_array [0 0 1 0] PSC_e_23_4 put /PSC_array Set + + % standard deviations of synaptic current amplitudes + /PSC_sd [PSC_e PSC_i] PSC_rel_sd mul def + /PSC_th_sd PSC_ext PSC_rel_sd mul def + + % standard deviations of delays + /delays_sd delays delay_rel_sd mul def + /delay_th_sd delay_th delay_th_rel_sd mul def + + % numbers of neurons from which to record spikes and membrane potentials + record_fraction_neurons_spikes + { + /num_neurons_rec_spikes + num_neurons{ frac_rec_spikes mul cvi } [2] Map + def + }{ + /num_neurons_rec_spikes + [num_layers num_pops_per_layer] n_rec_spikes LayoutArray + def + } ifelse + + record_fraction_neurons_voltage + { + /num_neurons_rec_voltage + num_neurons{ frac_rec_voltage mul cvi } [2] Map + def + }{ + /num_neurons_rec_voltage + [num_layers num_pops_per_layer] n_rec_voltage LayoutArray + def + } ifelse + +} def + + + +% the following variables are created here: +% neuron_subnet_GIDs +% poisson_GIDs +% dc_GIDs +% spike_detector_GIDs +% voltmeter_GIDs +% th_neuron_subnet_GID +% th_poisson_GID +% th_spike_detector_GID +/CreateNetworkNodes +{ + % create and configure neurons + neuron_model model_params SetDefaults + % arrays of GIDs: + % neuron subnets + /neuron_subnet_GIDs [num_layers num_pops_per_layer] 0 LayoutArray def + % spike detectors + /spike_detector_GIDs [num_layers num_pops_per_layer] 0 LayoutArray def + % voltmeters + /voltmeter_GIDs [num_layers num_pops_per_layer] 0 LayoutArray def + % Poisson generators + /poisson_GIDs [num_layers num_pops_per_layer] 0 LayoutArray def + % DC generators + /dc_GIDs [num_layers num_pops_per_layer] 0 LayoutArray def + 0 1 num_layers 1 sub + { + /layer_index Set + 0 ChangeSubnet % change to the root node + /subnet Create /layer_subnet Set + 0 1 num_pops_per_layer 1 sub + { + /population_index Set + layer_subnet ChangeSubnet + /subnet Create /population_subnet Set + population_subnet ChangeSubnet + % create neurons + /subnet Create /neuron_subnet Set + neuron_subnet ChangeSubnet + neuron_subnet_GIDs [layer_index population_index] neuron_subnet put + /neuron_subnet_GIDs Set + neuron_model num_neurons layer_index get population_index get + Create ; + + % initialize membrane potentials + neuron_subnet GetLocalNodes + { + dup /vp get /node_vp Set + << /V_m normal_rdvs node_vp get Random Vm0_std mul Vm0_mean add + >> SetStatus + } forall + + population_subnet ChangeSubnet + % create and configure stimulus and recording devices + /subnet Create /device_subnet Set + device_subnet ChangeSubnet + /spike_detector Create /this_spike_detector Set + this_spike_detector + << + % Set spike detector label for filenames. The GID of the spike + % detector and the process number are appended automatically. + /label spike_detector_label layer_index cvs join (_) join + population_index cvs join + /to_file save_cortical_spikes + >> SetStatus + spike_detector_GIDs [layer_index population_index] + this_spike_detector put + /spike_detector_GIDs Set + /voltmeter Create /this_voltmeter Set + this_voltmeter + << + /label voltmeter_label layer_index cvs join (_) join + population_index cvs join + /to_file save_voltages + >> SetStatus + voltmeter_GIDs [layer_index population_index] this_voltmeter put + /voltmeter_GIDs Set + /poisson_generator Create /this_poisson_generator Set + K_bg layer_index get population_index get /this_K_bg Set + this_poisson_generator + << + /rate this_K_bg bg_rate mul + >> SetStatus + + poisson_GIDs [layer_index population_index] this_poisson_generator + put + /poisson_GIDs Set + /dc_generator Create /this_dc_generator Set + this_dc_generator + << + /amplitude this_K_bg dc_amplitude mul + >> SetStatus + dc_GIDs [layer_index population_index] this_dc_generator put + /dc_GIDs Set + } for % loop over e and i populations + } for % loop over layers + + % create and configure thalamic neurons (parrots) and their Poisson inputs + 0 ChangeSubnet + n_thal 0 gt + { + /subnet Create /th_subnet Set + th_subnet ChangeSubnet + /subnet Create /th_neuron_subnet_GID Set + th_neuron_subnet_GID ChangeSubnet + /parrot_neuron n_thal Create ; + th_subnet ChangeSubnet + /subnet Create /th_device_subnet Set + th_device_subnet ChangeSubnet + /poisson_generator Create /th_poisson_GID Set + th_poisson_GID + << + /rate th_rate + /start th_start + /stop th_start th_duration add + >> SetStatus + record_thalamic_spikes + { + /spike_detector Create /th_spike_detector_GID Set + th_spike_detector_GID + << + % Set thalamic spike detector label. The GID of the spike + % detector and the process number are appended automatically. + /label th_spike_detector_label + /to_file save_thalamic_spikes + >> SetStatus + } if + } if +} def + + +/WriteGIDstoFile +{ + output_path (/) join GID_filename join + (w) ofsopen + ; /outputstream Set + Rank 0 eq + { + outputstream + } if + neuron_subnet_GIDs Flatten + { + GetGlobalNodes /GIDs Set + Rank 0 eq + { + GIDs Min <- (\t) <- GIDs Max <- (\n) <- + } if + } forall + Rank 0 eq + { + close + } if +} def + + +/ConnectNetworkNodes +{ + tic + + 0 1 num_layers 1 sub % target layer + { + /target_layer Set + 0 1 num_pops_per_layer 1 sub % target population + { + /target_pop Set + % get neuron IDs + + neuron_subnet_GIDs target_layer get target_pop get + dup GetGlobalNodes /target_nodes Set + GetLocalNodes /local_target_nodes Set + + % Determine the number of target neurons that will be used to + % compute the number of synapses. If in-degrees of the full-scale + % model are preserved, this means using the number of neurons from + % the full-scale model (only for computing the number of synapses). + preserve_K + { + /effective_num_targets full_scale_num_neurons target_layer get + target_pop get def + }{ + /effective_num_targets num_neurons target_layer get target_pop + get def + } ifelse + + 0 1 num_layers 1 sub % source layer + { + /source_layer Set + 0 1 num_pops_per_layer 1 sub % source population + { + /source_pop Set + + %%% local connections + + % get neuron IDs + neuron_subnet_GIDs source_layer get source_pop get + GetGlobalNodes + /source_nodes Set + + % Determine the number of source neurons that will be used + % to compute the number of synapses + preserve_K + { + /effective_num_sources full_scale_num_neurons + source_layer get source_pop get def + }{ + /effective_num_sources num_neurons source_layer get + source_pop get def + } ifelse + + % get connection probability + conn_probs + % pick row (target) in conn_probs + target_layer num_pops_per_layer mul target_pop add get + % pick column (source) in conn_probs + source_layer num_pops_per_layer mul source_pop add get + /this_conn Set % probability for this connection + + % Compute numbers of synapses assuming binomial degree + % distributions and allowing for multapses (see Potjans + % and Diesmann 2014 Cereb Cortex Eq. 1) + /prod effective_num_sources effective_num_targets mul def + ( log(1.-this_conn)/log((prod-1.)/prod) ) ExecMath + cvi /this_num_synapses Set + + this_num_synapses 0 gt + { + PSC_array target_layer get target_pop get source_layer + get source_pop get /mean_weight Set + + % Create label for target and source populations + /conn_label layers target_layer get (_) join + populations target_pop get join (-) join + layers source_layer get join (_) join + populations source_pop get join + def + + % fill the weight dictionary for Connect and insert it into the synapse dictionary + mean_weight 0 gt + { + weight_dict_exc /mu mean_weight put + weight_dict_exc /sigma PSC_sd source_pop get abs put + syn_dict /weight weight_dict_exc put + }{ + weight_dict_inh /mu mean_weight put + weight_dict_inh /sigma PSC_sd source_pop get abs put + syn_dict /weight weight_dict_inh put + } ifelse + + % fill the delay dictionary for Connect and insert it into the synapse dictionary + delay_dict /mu delays source_pop get put + delay_dict /sigma delays_sd source_pop get abs put + syn_dict /delay delay_dict put + + % fill the connectivity dictionary with the number of synapses to be used + conn_dict /N this_num_synapses put + + % Connect the populations + source_nodes + target_nodes + conn_dict + syn_dict + Connect + + } if % this_num_synapses > 0 + + } for % source population + } for % source layer + + n_thal 0 gt + { + % connections from thalamic neurons + + th_neuron_subnet_GID GetGlobalNodes + /source_nodes Set + + C_th target_layer get target_pop get /this_conn Set + + % Compute numbers of synapses assuming binomial degree + % distributions and allowing for multapses (see Potjans and + % Diesmann 2014 Cereb Cortex Eq. 1) + /prod n_thal effective_num_targets mul def + ( log(1.- this_conn)/log((prod-1.)/prod) ) ExecMath + cvi /this_num_synapses Set + + this_num_synapses 0 gt + { + + % create label for current target population + /th_conn_label layers target_layer get (_) join + populations target_pop get join + def + + % fill the weight dictionary for Connect + weight_dict_exc /mu PSC_ext put + weight_dict_exc /sigma PSC_th_sd abs put + + % insert the weight dictionary into the synapse dictionary + syn_dict /weight weight_dict_exc put + + % fill the delay dictionary for Connect + delay_dict /mu delay_th put + delay_dict /sigma delay_th_sd abs put + + % insert the delay dictionary into the synapse dictionary + syn_dict /delay delay_dict put + + % fill the connectivity dictionary with the number of synapses to be used + conn_dict /N this_num_synapses put + + % Connect the thalamus + source_nodes + target_nodes + conn_dict + syn_dict + Connect + + } if % this_num_synapses > 0 + } if % n_thal > 0 + + % Connect devices + + % Connect to the spike detector + target_nodes + % record from a continuous range of IDs + % (appropriate for networks without topology) + num_neurons_rec_spikes target_layer get target_pop get + Take + spike_detector_GIDs target_layer get target_pop get + 1 arraystore + /all_to_all + Connect + + % Connect to the voltmeter + voltmeter_GIDs target_layer get target_pop get + 1 arraystore + target_nodes + % record from a continuous range of IDs + num_neurons_rec_voltage target_layer get target_pop get + Take + /all_to_all + Connect + + % Connect to the Poisson generators + poisson_GIDs target_layer get target_pop get + 1 arraystore + target_nodes + /all_to_all + << /weight PSC_ext /delay delays 0 get >> + Connect + + % Connect to the DC generators + dc_GIDs target_layer get target_pop get + 1 arraystore + target_nodes + /all_to_all + Connect + + } for % target population + } for % target layer + + n_thal 0 gt + { + % Connect thalamic poisson_generator to thalamic neurons (parrots) + th_poisson_GID + 1 arraystore + th_neuron_subnet_GID GetGlobalNodes + /all_to_all + Connect + } if + + record_thalamic_spikes n_thal 0 gt and + { + % Connect thalamic neurons to spike detector + th_neuron_subnet_GID GetGlobalNodes + th_spike_detector_GID + 1 arraystore + /all_to_all + Connect + } if + + toc /ConnectTime Set +} def + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% Executive section %%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% load parameters +(user_params) run +(sim_params) run +(network_params) run + +CheckParameters + +PrepareSimulation + +DerivedParameters + +CreateNetworkNodes + +WriteGIDstoFile + +ConnectNetworkNodes + +tic +t_sim Simulate +toc /SimTime Set + +Rank 0 eq +{ + (Connecting took ) ConnectTime cvs join ( s\n) join + (Simulating took ) join SimTime cvs join ( s) join + M_INFO + message +} if + diff --git a/examples/nest/Potjans_2014/network_params.sli b/examples/nest/Potjans_2014/network_params.sli new file mode 100644 index 0000000000..f7436ac1b6 --- /dev/null +++ b/examples/nest/Potjans_2014/network_params.sli @@ -0,0 +1,162 @@ +/* + * network_params.sli + * + * This file is part of NEST. + * + * Copyright (C) 2004 The NEST Initiative + * + * NEST 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 2 of the License, or + * (at your option) any later version. + * + * NEST 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 NEST. If not, see . + * + */ + +/* + Contains: + - network parameters + - single-neuron parameters + - stimulus parameters +*/ + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% Network parameters %%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% area of network in mm^2; scales numbers of neurons +% use 1 for the full-size network (77,169 neurons) +/area 1 def + +% whether to use full-scale in-degrees when downscaling the number of neurons +% When preserve_K is false, the full-scale connection probabilities are used. +/preserve_K true def + +/layers [(L23) (L4) (L5) (L6)] def +/populations [(e) (i)] def + +/full_scale_num_neurons + [[20683 % layer 2/3 e + 5834 ] % layer 2/3 i + [21915 % layer 4 e + 5479 ] % layer 4 i + [4850 % layer 5 e + 1065 ] % layer 5 i + [14395 % layer 6 e + 2948 ]] % layer 6 i +def + +% mean EPSP amplitude (mV) for all connections except L4e->L2/3e +/PSP_e .15 def +% mean EPSP amplitude (mv) for L4e->L2/3e connections +% The weight from L4e to L23e is chosen such that the results in the paper can be reproduced. The weigh deviates from the one specified in the paper by a factor of two. +/PSP_e_23_4 PSP_e 2 mul def +% standard deviation of PSC amplitudes relative to mean PSC amplitudes +/PSC_rel_sd 0.1 def +% IPSP amplitude relative to EPSP amplitude +/g -4. def + +% probabilities for >=1 connection between neurons in the given populations +% columns correspond to source populations; rows to target populations +% source 2/3e 2/3i 4e 4i 5e 5i 6e 6i +/conn_probs [[0.1009 0.1689 0.0437 0.0818 0.0323 0. 0.0076 0. ] + [0.1346 0.1371 0.0316 0.0515 0.0755 0. 0.0042 0. ] + [0.0077 0.0059 0.0497 0.135 0.0067 0.0003 0.0453 0. ] + [0.0691 0.0029 0.0794 0.1597 0.0033 0. 0.1057 0. ] + [0.1004 0.0622 0.0505 0.0057 0.0831 0.3726 0.0204 0. ] + [0.0548 0.0269 0.0257 0.0022 0.06 0.3158 0.0086 0. ] + [0.0156 0.0066 0.0211 0.0166 0.0572 0.0197 0.0396 0.2252] + [0.0364 0.001 0.0034 0.0005 0.0277 0.008 0.0658 0.1443]] + def + +% mean dendritic delays for excitatory and inhibitory transmission (ms) +/delays [1.5 0.75] def +% standard deviation relative to mean delays +/delay_rel_sd 0.5 def +% connection pattern used in connection calls connecting populations +/conn_dict << /rule /fixed_total_number >> def +% weight distribution of connections between populations +/weight_dict_exc << /distribution /normal_clipped /low 0.0 >> def +/weight_dict_inh << /distribution /normal_clipped /high 0.0 >> def +% delay distribution of connections between populations +/delay_dict << /distribution /normal_clipped /low 0.1 >> def +% default synapse dictionary +/syn_dict << /model /static_synapse >> def + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% Single-neuron parameters %%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +/neuron_model /iaf_psc_exp def % neuron model. For PSP-to-PSC conversion to + % be correct, synapses should be current-based + % with an exponential time course +/Vm0_mean -58.0 def % mean of initial membrane potential (mV) +/Vm0_std 10.0 def % std of initial membrane potential (mV) + +% neuron model parameters +/model_params << /tau_m 10. % membrane time constant (ms) + /tau_syn_ex 0.5 % excitatory synaptic time constant (ms) + /tau_syn_in 0.5 % inhibitory synaptic time constant (ms) + /t_ref 2. % absolute refractory period (ms) + /E_L -65. % resting membrane potential (mV) + /V_th -50. % spike threshold (mV) + /C_m 250. % membrane capacitance (pF) + /V_reset -65. % reset potential (mV) + >> def + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% Stimulus parameters %%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% rate of background Poisson input at each external input synapse (spikes/s) +/bg_rate 8. def +% DC amplitude at each external input synapse (pA) +% This is relevant for reproducing Potjans & Diesmann (2014) Fig. 7. +/dc_amplitude 0. def +% in-degrees for background input +/K_bg [[1600 % 2/3e + 1500] % 2/3i + [2100 % 4e + 1900] % 4i + [2000 % 5e + 1900] % 5i + [2900 % 6e + 2100]] % 6i + def + +% optional additional thalamic input (Poisson) +% Set n_thal to 0 to avoid this input. +% For producing Potjans & Diesmann (2014) Fig. 10, n_thal=902 was used. +% Note that the thalamic rate here reproduces the simulation results +% shown in the paper, and differs from the rate given in the text. +/n_thal 0 def % size of thalamic population +/th_start 700. def % onset of thalamic input (ms) +/th_duration 10. def % duration of thalamic input (ms) +/th_rate 120. def % rate of thalamic neurons (spikes/s) +/PSP_ext 0.15 def % mean EPSP amplitude (mV) for external input + +% connection probabilities for thalamic input +/C_th [[0.0 % 2/3e + 0.0 ] % 2/3i + [0.0983 % 4e + 0.0619] % 4i + [0.0 % 5e + 0.0 ] % 5i + [0.0512 % 6e + 0.0196]] % 6i + def + +% mean delay of thalamic input (ms) +/delay_th 1.5 def +% standard deviation relative to mean delay of thalamic input +/delay_th_rel_sd 0.5 def + diff --git a/examples/nest/Potjans_2014/plot_rates.py b/examples/nest/Potjans_2014/plot_rates.py new file mode 100644 index 0000000000..a2087ace3c --- /dev/null +++ b/examples/nest/Potjans_2014/plot_rates.py @@ -0,0 +1,109 @@ +# -*- coding: utf-8 -*- +# +# plot_rates.py +# +# This file is part of NEST. +# +# Copyright (C) 2004 The NEST Initiative +# +# NEST 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 2 of the License, or +# (at your option) any later version. +# +# NEST 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 NEST. If not, see . + +import numpy as np +import matplotlib.pyplot as plt +import glob +import sys + +# parameter + +# beginning and end of time interval +t_start = 300 +t_stop = 700 + +# size of recorded number of neurons in each population +# the number of recorded neurons is chosen in sim_params.sli and can either be determined by the full_scale_num_neurons*area*frac_rec_spikes or a set number of neurons (n_rec_spike) +pop_sizes = [[20683,5834],[21915,5479],[4850,1065],[14395,2948]] +frac_rec_spikes = 0.1 +area = 1.0 +for i in range(8): + layer = i/2 + pop = i%2 + pop_sizes[layer][pop] *= area*frac_rec_spikes + + +# relative path to the data files +path = 'data' + +# list of dictionaries, one dictionary containing neuroron number and spike times +spikes = [{} for i in range(8)] + +# read out spikes within the specified time interval + +for i in range(8): + layer = i/2 + pop = i%2 + filestart = path + '/spikes_' + str(layer) + '_' + str(pop) + '*' + filelist = glob.glob(filestart) + + for filename in filelist: + input_file = open(filename,'r') + while True: + line = input_file.readline() + data = line.split() + if len(data) == 0: + break + t_spike = float(data[1]) + if t_spike > t_stop: + break + neuron_gid = int(data[0]) + if t_spike>=t_start: + if neuron_gid in spikes[i]: + spikes[i][neuron_gid].append(t_spike) + else: + spikes[i][neuron_gid] = [t_spike] + +# plot spike times in raster plot and bar plot with the average firing rates of each population + +color = ['#595289', '#af143c'] +pops = ['23E', '23I', '4E', '4I', '5E', '5I', '6E', '6I'] +rates = np.zeros(8) +fig, axarr = plt.subplots(1,2) + +# plot raster plot +gid_count = 0 +for i in range(8)[::-1]: + layer = i/2 + pop = i%2 + rate = 0.0 + for neuron_gid in spikes[i]: + t_spikes = spikes[i][neuron_gid] + nr_spikes = len(t_spikes) + rate += 1000*nr_spikes/(t_stop-t_start)*1/float(pop_sizes[layer][pop]) + gid = gid_count*np.ones(nr_spikes) + axarr[0].plot(t_spikes, gid, '.', color=color[pop]) + gid_count += 1 + rates[i] = rate + +# plot bar plot +axarr[1].barh(np.arange(0,8,1)+0.1,rates[::-1],color=color[::-1]*4) + +# set labels +axarr[0].set_ylim((0.0,gid_count)) +axarr[0].set_yticklabels([]) +axarr[0].set_xlabel('time (ms)') +axarr[1].set_ylim((0.0,8.5)) +axarr[1].set_yticks(np.arange(0.5,8.5,1.0)) +axarr[1].set_yticklabels(pops[::-1]) +axarr[1].set_xlabel('rate (spikes/s)') + +plt.show() diff --git a/examples/nest/Potjans_2014/run_microcircuit.sh b/examples/nest/Potjans_2014/run_microcircuit.sh new file mode 100755 index 0000000000..3544fa3846 --- /dev/null +++ b/examples/nest/Potjans_2014/run_microcircuit.sh @@ -0,0 +1,73 @@ +# -*- coding: utf-8 -*- +# +# run_microcircuit.sh +# +# This file is part of NEST. +# +# Copyright (C) 2004 The NEST Initiative +# +# NEST 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 2 of the License, or +# (at your option) any later version. +# +# NEST 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 NEST. If not, see . + +#!/bin/bash + +# creates output folder if it does not exist yet, creates sim_script.sh, +# and submits it to the queue +# +# adapt to your system as necessary + +# read in parameters and paths from user_params.sli and sim_params.sli +# output directory +path=`egrep '/output_path' user_params.sli|cut -f 2 -d '('|cut -f 1 -d ')'` +# number of nodes +n_nodes=`egrep '/n_nodes' sim_params.sli|cut -f 2 -d ' '` +# number of processors per node +n_procs_per_node=`egrep '/n_procs_per_node' sim_params.sli|cut -f 2 -d ' '` +# walltime +walltime=`egrep '/walltime' sim_params.sli|cut -f 2 -d '('|cut -f 1 -d ')'` +# memory allocation +memory=`egrep '/memory' sim_params.sli|cut -f 2 -d '('|cut -f 1 -d ')'` + +# path for mpi +mpi_path=`egrep '/mpi' user_params.sli|cut -f 2 -d '('|cut -f 1 -d ')'` +# path for nest +nest_path=`egrep '/nest_path' user_params.sli|cut -f 2 -d '('|cut -f 1 -d ')'` +# standard output file name +output=`egrep '/std_out' sim_params.sli|cut -f 2 -d '('|cut -f 1 -d ')'` +# error output file name +errors=`egrep '/error_out' sim_params.sli|cut -f 2 -d '('|cut -f 1 -d ')'` + +# copy simulation scripts to output directory +mkdir -p $path +cp 'user_params.sli' $path +cp 'sim_params.sli' $path +cp 'network_params.sli' $path +cp 'microcircuit.sli' $path +cd $path + +# create sim_script.sh +echo > sim_script.sh +chmod 755 sim_script.sh + +echo "#PBS -o $path/$output" >> sim_script.sh +echo "#PBS -e $path/$errors" >> sim_script.sh +echo "#PBS -l walltime=$walltime" >> sim_script.sh +echo "#PBS -l mem=$memory" >> sim_script.sh +echo ". $mpi_path" >> sim_script.sh +echo "cd $path/" >> sim_script.sh +echo -n "mpirun -machinefile \$PBS_NODEFILE " >> sim_script.sh +echo "$nest_path $path/microcircuit.sli" >> sim_script.sh + +# The variable PBS_NODEFILE is set dynamically when invoking qsub +qsub -l nodes=$n_nodes:ppn=$n_procs_per_node sim_script.sh + diff --git a/examples/nest/Potjans_2014/sim_params.sli b/examples/nest/Potjans_2014/sim_params.sli new file mode 100644 index 0000000000..690b81aa13 --- /dev/null +++ b/examples/nest/Potjans_2014/sim_params.sli @@ -0,0 +1,108 @@ +/* + * sim_params.sli + * + * This file is part of NEST. + * + * Copyright (C) 2004 The NEST Initiative + * + * NEST 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 2 of the License, or + * (at your option) any later version. + * + * NEST 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 NEST. If not, see . + * + */ + +/* + Contains: + - simulation parameters + - recording parameters +*/ + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% Simulation parameters %%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +/t_sim 1000.0 def % simulated time (ms) +/dt 0.1 def % simulation step (ms). Default is 0.1 ms. +/allgather true def % communication protocol + +% master seed for random number generators +% actual seeds will be master_seed ... master_seed + 2*n_vp +% ==>> different master seeds must be spaced by at least 2*n_vp + 1 +% see Gewaltig et al. (2012) for details +/master_seed 123456 def % changes rng_seeds and grng_seed + +/n_nodes 1 def % number of MPI nodes +/n_procs_per_node 24 def % number of MPI processes per node +/n_vp n_procs_per_node n_nodes mul def % number of virtual processes +% This should be an integer multiple of the number of processes +% See Morrison et al. (2005) Neural Comput +/walltime (8:0:0) def % walltime for simulation +/memory (4gb) def % total memory for simulation + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% Recording parameters %%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +/overwrite_existing_files true def + +% whether to record spikes from a fixed fraction of neurons in each population +% If false, a fixed number of neurons is recorded in each population. +% record_fraction_neurons_spikes true with f_rec_spikes 1. records all spikes +/record_fraction_neurons_spikes true def + +record_fraction_neurons_spikes +{ + /frac_rec_spikes 0.1 def +}{ + /n_rec_spikes 100 def +} ifelse + +% whether to record voltage from a fixed fraction of neurons in each population +/record_fraction_neurons_voltage true def + +record_fraction_neurons_voltage +{ + /frac_rec_voltage 0.02 def +}{ + /n_rec_voltage 20 def +} ifelse + +% whether to write any recorded cortical spikes to file +/save_cortical_spikes true def + +% whether to write any recorded membrane potentials to file +/save_voltages true def + +% whether to record thalamic spikes (only used when n_thal in +% network_params.sli is nonzero) +/record_thalamic_spikes true def + +% whether to write any recorded thalamic spikes to file +/save_thalamic_spikes true def + +% name of file to which to write global IDs +/GID_filename (population_GIDs.dat) def + +% stem for spike detector file labels +/spike_detector_label (spikes_) def + +% stem for voltmeter file labels +/voltmeter_label (voltages_) def + +% stem for thalamic spike detector file labels +/th_spike_detector_label (th_spikes_) def + +% file name for standard output +/std_out (output.txt) def + +% file name for error output +/error_out (errors.txt) def diff --git a/examples/nest/Potjans_2014/spike_analysis_www.py b/examples/nest/Potjans_2014/spike_analysis_www.py new file mode 100644 index 0000000000..d86668b6f5 --- /dev/null +++ b/examples/nest/Potjans_2014/spike_analysis_www.py @@ -0,0 +1,197 @@ +# -*- coding: utf-8 -*- +# +# spike_analysis_www.py +# +# This file is part of NEST. +# +# Copyright (C) 2004 The NEST Initiative +# +# NEST 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 2 of the License, or +# (at your option) any later version. +# +# NEST 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 NEST. If not, see . + +# Merges spike files, produces raster plots, calculates and plots firing rates + +import numpy as np +import glob +import matplotlib.pyplot as plt + +datapath = '../data/' + +# get simulation time and numbers of neurons recorded from sim_params.sli + +f = open(datapath + 'sim_params.sli', 'r') +for line in f: + if 't_sim' in line: + T = float(line.split()[1]) + if '/record_fraction_neurons_spikes' in line: + record_frac = line.split()[1] +f.close() + +f = open(datapath + 'sim_params.sli', 'r') +for line in f: + if record_frac == 'true': + if 'frac_rec_spikes' in line: + frac_rec = float(line.split()[1]) + else: + if 'n_rec_spikes' in line: + n_rec = int(line.split()[1]) +f.close() + + +T_start = 200. # starting point of analysis (to avoid transients) + +# load GIDs + +gidfile = open(datapath + 'population_GIDs.dat','r') +gids = [] +for l in gidfile: + a = l.split() + gids.append([int(a[0]),int(a[1])]) +print 'Global IDs:' +print gids +print + +# number of populations + +num_pops = len(gids) +print 'Number of populations:' +print num_pops +print + +# first GID in each population + +raw_first_gids = [gids[i][0] for i in np.arange(len(gids))] + +# population sizes + +pop_sizes = [gids[i][1]-gids[i][0]+1 for i in np.arange(len(gids))] + +# numbers of neurons for which spikes were recorded + +if record_frac == 'true': + rec_sizes = [int(pop_sizes[i]*frac_rec) for i in xrange(len(pop_sizes))] +else: + rec_sizes = [n_rec]*len(pop_sizes) + +# first GID of each population once device GIDs are dropped + +first_gids=[int(1 + np.sum(pop_sizes[:i])) for i in np.arange(len(pop_sizes))] + +# last GID of each population once device GIDs are dropped + +last_gids = [int(np.sum(pop_sizes[:i+1])) for i in np.arange(len(pop_sizes))] + +# convert lists to a nicer format, i.e. [[2/3e, 2/3i], []....] + +Pop_sizes =[pop_sizes[i:i+2] for i in xrange(0,len(pop_sizes),2)] +print 'Population sizes:' +print Pop_sizes +print + +Raw_first_gids =[raw_first_gids[i:i+2] for i in xrange(0,len(raw_first_gids),2)] + +First_gids = [first_gids[i:i+2] for i in xrange(0,len(first_gids),2)] + +Last_gids = [last_gids[i:i+2] for i in xrange(0,len(last_gids),2)] + +# total number of neurons in the simulation + +num_neurons = last_gids[len(last_gids)-1] +print 'Total number of neurons:' +print num_neurons +print + +# load spikes from gdf files, correct GIDs and merge them in population files, +# and store spike trains + +# will contain neuron id resolved spike trains +neuron_spikes = [[] for i in np.arange(num_neurons+1)] +# container for population-resolved spike data +spike_data= [[[],[]],[[],[]],[[],[]],[[],[]],[[],[]],[[],[]],[[],[]],[[],[]]] + +counter = 0 + +for layer in ['0','1','2','3']: + for population in ['0','1']: + output = datapath + 'population_spikes-'+ layer+'-'+population+'.gdf' + file_pattern = datapath + 'spikes_'+ layer+'_'+population+'*' + files = glob.glob(file_pattern) + print 'Merge '+str(len(files))+' spike files from L'+layer+'P'+population + if files: + merged_file = open(output,'w') + for f in files: + data = open(f,'r') + for l in data : + a = l.split() + a[0] = int(a[0]) + a[1] = float(a[1]) + raw_first_gid = Raw_first_gids[int(layer)][int(population)] + first_gid = First_gids[int(layer)][int(population)] + a[0] = a[0] - raw_first_gid + first_gid + + if(a[1] > T_start): # discard data in the start-up phase + spike_data[counter][0].append(num_neurons-a[0]) + spike_data[counter][1].append(a[1]-T_start) + neuron_spikes[a[0]].append(a[1]-T_start) + + converted_line = str(a[0]) + '\t' + str(a[1]) +'\n' + merged_file.write(converted_line) + data.close() + merged_file.close() + counter +=1 + + +clrs=['0','0.5','0','0.5','0','0.5','0','0.5'] +plt.ion() + +# raster plot + +plt.figure(1) +counter = 1 +for j in np.arange(num_pops): + for i in np.arange(first_gids[j],first_gids[j]+rec_sizes[j]): + plt.plot(neuron_spikes[i],np.ones_like(neuron_spikes[i])+sum(rec_sizes)-counter,'k o',ms=1, mfc=clrs[j],mec=clrs[j]) + counter+=1 +plt.xlim(0,T-T_start) +plt.ylim(0,sum(rec_sizes)) +plt.xlabel(r'time (ms)') +plt.ylabel(r'neuron id') +plt.savefig(datapath + 'rasterplot.png') + + +# firing rates + +rates = [] +temp = 0 + +for i in np.arange(num_pops): + for j in np.arange(first_gids[i], last_gids[i]): + temp+= len(neuron_spikes[j]) + rates.append(temp/(rec_sizes[i]*(T-T_start))*1e3) + temp = 0 + +print +print 'Firing rates:' +print rates + +plt.figure(2) +ticks= np.arange(num_pops) +plt.bar(ticks, rates, width=0.9, color='k') +xticklabels = ['L2/3e','L2/3i','L4e','L4i','L5e','L5i','L6e','L6i'] +plt.setp(plt.gca(), xticks=ticks+0.5, xticklabels=xticklabels) +plt.xlabel(r'subpopulation') +plt.ylabel(r'firing rate (spikes/s)') +plt.savefig(datapath + 'firing_rates.png') + +plt.show() + diff --git a/examples/nest/Potjans_2014/user_params.sli b/examples/nest/Potjans_2014/user_params.sli new file mode 100644 index 0000000000..154bc7edb9 --- /dev/null +++ b/examples/nest/Potjans_2014/user_params.sli @@ -0,0 +1,33 @@ +/* + * user_params.sli + * + * This file is part of NEST. + * + * Copyright (C) 2004 The NEST Initiative + * + * NEST 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 2 of the License, or + * (at your option) any later version. + * + * NEST 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 NEST. If not, see . + * + */ + +% absolute path to which the output files should be written +/output_path (/path_to_data/data) +def + +% path to the mpi shell script +% can be left out if set beforehand +/mpi (/path_to_mpi_script/my_mpi_script.sh) +def + +% path to NEST +/nest_path (/path_to_nest_install_folder/bin/nest) def diff --git a/examples/nest/balancedneuron-2.sli b/examples/nest/balancedneuron-2.sli index 7345083568..b7152d1bcd 100644 --- a/examples/nest/balancedneuron-2.sli +++ b/examples/nest/balancedneuron-2.sli @@ -29,8 +29,8 @@ % Try changing the value of /ipsc and see what happens. %% -/arr (1.2) require -/arr using +(arraylib) run +/arraylib using ResetKernel diff --git a/examples/nest/brunel-2000.sli b/examples/nest/brunel-2000.sli index 099b9169b5..699fbc44bb 100644 --- a/examples/nest/brunel-2000.sli +++ b/examples/nest/brunel-2000.sli @@ -1,5 +1,5 @@ /* - * brunel.sli + * brunel-2000.sli * * This file is part of NEST. * @@ -71,11 +71,6 @@ /simtime 1000.0 def % simulation time [ms] /dt 0.1 def % simulation step length [ms] -% Number of virtual processes in the simulation. -% When using MPI, the mpirun call determines the number -% of MPI processes (=program instances). The number of threads -% per process is total_num_virtual_procs / # MPI processes. -/total_num_virtual_procs 4 def %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % NO USER-SERVICABLE PARTS BELOW @@ -175,11 +170,29 @@ ComputePSPnorm /J_max_unit Set ResetKernel % clear all existing network elements M_WARNING setverbosity + +% Number of threads per program instance. When using MPI, the mpirun +% call determines the number of MPI processes (= program instances). +% The total number of virtual processes is +% #MPI processes x local_num_threads. +% +% The number of local_num_threads can be given to the script using +% the --userargs commandline switch like this: +% nest --userargs=threads=4 script.sli +% +% If it is not given, it defaults to 2 +statusdict/userargs :: size 1 geq +{ + 0 get (=) breakup 1 get int /local_num_threads Set +} +{ + 2 /local_num_threads Set +} ifelse + % set resolution and total/local number of threads 0 << /resolution dt - /total_num_virtual_procs total_num_virtual_procs - /print_time true + /local_num_threads local_num_threads /overwrite_files true >> SetStatus @@ -233,7 +246,7 @@ M_WARNING setverbosity /exsd /spike_detector Create def exsd << - /label (brunel-2-ex) + /label (brunel-2-ex-threaded) /withtime true % record time of spikes /withgid true % and the global ID of the neuron /to_file true % write results to a file @@ -244,7 +257,7 @@ M_WARNING setverbosity /insd /spike_detector Create def insd << - /label (brunel-2-in) + /label (brunel-2-in-threaded) /withtime true % record time of spikes /withgid true % and the global ID of the neuron /to_file true % write results to a file @@ -258,14 +271,42 @@ M_WARNING setverbosity /static_synapse_hom_wd /syn_in << /weight JI >> CopyModel (Connecting excitatory neurons.) = - expoisson E_neurons /syn_ex DivergentConnect - E_neurons E_net CE /syn_ex RandomConvergentConnect - I_neurons E_net CI /syn_in RandomConvergentConnect + % expoisson E_neurons /syn_ex DivergentConnect + expoisson 1 arraystore E_neurons /all_to_all /syn_ex Connect + + /target_ids E_net GetLocalNodes def + /ns [ target_ids length ] { pop CE } Table def + /empty [ target_ids length ] { pop [] } Table def + /source_ids E_net GetGlobalNodes def + % source_ids target_ids ns empty empty true true /syn_ex RandomConvergentConnect_ia_ia_ia_daa_daa_b_b_l + % E_neurons E_net CE /syn_ex RandomConvergentConnect + E_neurons E_neurons << /rule /fixed_indegree /indegree CE >> /syn_ex Connect + + /ns [ target_ids length ] { pop CI } Table def + /source_ids I_net GetGlobalNodes def + % source_ids target_ids ns empty empty true true /syn_in RandomConvergentConnect_ia_ia_ia_daa_daa_b_b_l + % I_neurons E_net CI /syn_in RandomConvergentConnect + I_neurons E_neurons << /rule /fixed_indegree /indegree CI >> /syn_in Connect (Connecting inhibitory population.) = - inpoisson I_neurons /syn_ex DivergentConnect - E_neurons I_net CE /syn_ex RandomConvergentConnect - I_neurons I_net CI /syn_in RandomConvergentConnect + % inpoisson I_neurons /syn_ex DivergentConnect + inpoisson 1 arraystore I_neurons /all_to_all /syn_ex Connect + + + /target_ids I_net GetLocalNodes def + /ns [ target_ids length ] { pop CE } Table def + /empty [ target_ids length ] { pop [] } Table def + /source_ids E_net GetGlobalNodes def + %source_ids target_ids ns empty empty true true /syn_ex RandomConvergentConnect_ia_ia_ia_daa_daa_b_b_l + %E_neurons I_net CE /syn_ex RandomConvergentConnect + E_neurons I_neurons << /rule /fixed_indegree /indegree CE >> /syn_ex Connect + + + /ns [ target_ids length ] { pop CI } Table def + /source_ids I_net GetGlobalNodes def + % source_ids target_ids ns empty empty true true /syn_in RandomConvergentConnect_ia_ia_ia_daa_daa_b_b_l + % I_neurons I_net CI /syn_in RandomConvergentConnect + I_neurons I_neurons << /rule /fixed_indegree /indegree CI >> /syn_in Connect % Spike detectors are connected to the first Nrec neurons in each % population. Since neurons are equal and connectivity is homogeneously @@ -273,13 +314,15 @@ M_WARNING setverbosity % from each population (Connecting spike detectors.) = - E_neurons Nrec Take exsd ConvergentConnect % pick the first 500 neurons - I_neurons Nrec Take insd ConvergentConnect + % E_neurons Nrec Take exsd ConvergentConnect % pick the first 500 neurons + % I_neurons Nrec Take insd ConvergentConnect + E_neurons Nrec Take exsd 1 arraystore /all_to_all Connect % pick the first 500 neurons + I_neurons Nrec Take insd 1 arraystore /all_to_all Connect toc /BuildCPUTime Set - /syn_ex GetDefaults /num_connections get /n_ex_syn Set - /syn_in GetDefaults /num_connections get /n_in_syn Set + /syn_ex GetDefaults /num_connections get /n_ex_syn Set + /syn_in GetDefaults /num_connections get /n_in_syn Set %%% SIMULATION SECTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -290,6 +333,7 @@ M_WARNING setverbosity % write a little report (\nBrunel Network Simulation) = + (Number of Threads : ) =only local_num_threads = (Number of Neurons : ) =only N = (Number of Synapses: ) =only 0 GetStatus /num_connections get = ( Excitatory : ) =only n_ex_syn = diff --git a/examples/nest/brunel-2000_newconnect.sli b/examples/nest/brunel-2000_newconnect.sli new file mode 100644 index 0000000000..b6dbd79370 --- /dev/null +++ b/examples/nest/brunel-2000_newconnect.sli @@ -0,0 +1,345 @@ +/* + * brunel-2000_newconnect.sli + * + * This file is part of NEST. + * + * Copyright (C) 2004 The NEST Initiative + * + * NEST 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 2 of the License, or + * (at your option) any later version. + * + * NEST 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 NEST. If not, see . + * + */ + +/* + Brunel Network + + The SLI code in this file creates a sparsely coupled network of + excitatory and inhibitory neurons. Connections within and across + both populations are created at random. Both neuron populations + receive Poissonian background input. The spike output of 50 + neurons from each population are recorded. Neurons are modeled + as leaky integrate-and-fire neurons with current-injecting synapses + (alpha functions). The model is based on + + Nicolas Brunel + Dynamics of sparsely connected networks of excitatory + and inhibitory spiking neurons + Journal of Computational Neuroscience, 2000, vol 8, pp 183-208. + + There are two differences to Brunel's model: we use alpha + functions instead of delta for synaptic currents, and our neurons + reset to the resting potential (0 mv) instead of to half-way + between resting potential and threshold. + + This example shows how to + + - organize subpopulations in subnets + - instrument a network with injection and recording devices + - record data to files + - define own functions + - set parameters in a simple way + - communicate with the user in a simple way + + Abigail Morrison, Marc-Oliver Gewaltig, Hans Ekkehard Plesser +*/ + +%%% PARAMETER SECTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% define all relevant parameters: changes should be made here +% all data is place in the userdict dictionary + +/order 2500 def % scales size of network (total 5*order neurons) + +% case C : asynchronous irregullar +/g 5.0 def % rel strength, inhibitory synapses +/eta 2.0 def % nu_ext / nu_thresh + +% case D : slow oscillations +%/g 4.5 def % rel strength, inhibitory synapses +%/eta 0.95 def % nu_ext / nu_thresh + +/simtime 1000.0 def % simulation time [ms] +/dt 0.1 def % simulation step length [ms] + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% NO USER-SERVICABLE PARTS BELOW +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%% FUNCTION SECTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% Take spike detector, find total number of spikes registered, +% return average rate per neuron in Hz. +% NOTE: If you are running with several MPI processes, this +% function only gives an approximation to the true rate. +% +% spike_det ComputeRate -> rate +/ComputeRate +{ + << >> begin % anonymous dictionary for local variables + + /sdet Set + + % We need to guess how many neurons we record from. + % This assumes an even distribution of nodes across + % processes, as well as homogeneous activity in the + % network. So this is really a hack. NEST needs better + % support for rate calculations, such as giving the + % number of neurons recorded from by each spike detector. + + userdict /Nrec get cvd NumProcesses div /nnrn Set + sdet /n_events get nnrn userdict /simtime get mul div + 1000 mul % convert from mHz to Hz, leave on stack + + end +} bind % optional, improves performance +def + + +% Compute the maximum of postsynaptic potential +% for a synaptic input current of unit amplitude +% (1 pA) +/ComputePSPnorm +{ + % calculate the normalization factor for the PSP + ( + a = tauMem / tauSyn; + b = 1.0 / tauSyn - 1.0 / tauMem; + % time of maximum + t_max = 1.0/b * (-LambertWm1(-exp(-1.0/a)/a)-1.0/a); + % maximum of PSP for current of unit amplitude + exp(1.0)/(tauSyn*CMem*b) * ((exp(-t_max/tauMem) - exp(-t_max/tauSyn)) / b - t_max*exp(-t_max/tauSyn)) + ) ExecMath +} +def + +%%% PREPARATION SECTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +/NE 4 order mul cvi def % number of excitatory neurons +/NI 1 order mul cvi def % number of inhibitory neurons +/N NI NE add def % total number of neurons + +/epsilon 0.1 def % connectivity +/CE epsilon NE mul cvi def % number of excitatory synapses on neuron +/CI epsilon NI mul cvi def % number of inhibitory synapses on neuron +/C CE CI add def % total number of internal synapses per n. +/Cext CE def % number of external synapses on neuron + +/tauMem 20.0 def % neuron membrane time constant [ms] +/CMem 1.0 def % membrane capacity [pF] +/tauSyn 0.5 def % synaptic time constant [ms] +/tauRef 2.0 def % refractory time [ms] +/U0 0.0 def % resting potential [mV] +/theta 20.0 def % threshold + + +% amplitude of PSP given 1pA current +ComputePSPnorm /J_max_unit Set + +% synaptic weights, scaled for our alpha functions, such that +% for constant membrane potential, the peak amplitude of the PSP +% equals J + +/delay 1.5 def % synaptic delay, all connections [ms] +/J 0.1 def % synaptic weight [mV] +/JE J J_max_unit div def % synaptic weight [pA] +/JI g JE mul neg def % inhibitory + +% threshold rate, equivalent rate of events needed to +% have mean input current equal to threshold +/nu_thresh ((theta * CMem) / (JE*CE*exp(1)*tauMem*tauSyn)) ExecMath def +/nu_ext eta nu_thresh mul def % external rate per synapse +/p_rate nu_ext Cext mul 1000. mul def % external input rate per neuron + % must be given in Hz + +% number of neurons per population to record from +/Nrec 50 def + + +%%% CONSTRUCTION SECTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +ResetKernel % clear all existing network elements +M_WARNING setverbosity + +% Number of threads per program instance. When using MPI, the mpirun +% call determines the number of MPI processes (= program instances). +% The total number of virtual processes is +% #MPI processes x local_num_threads. +% +% The number of local_num_threads can be given to the script using +% the --userargs commandline switch like this: +% nest --userargs=threads=4 script.sli +% +% If it is not given, it defaults to 2 +statusdict/userargs :: size 1 geq +{ + 0 get (=) breakup 1 get int /local_num_threads Set +} +{ + 2 /local_num_threads Set +} ifelse + +% set resolution and total/local number of threads +0 << + /resolution dt + /local_num_threads local_num_threads + /overwrite_files true +>> SetStatus + + tic % start timer on construction + +% Setting neuron default parameters + + (Configuring neuron parameters.) = + /iaf_psc_alpha + << + /tau_m tauMem + /tau_syn_ex tauSyn + /tau_syn_in tauSyn + /t_ref tauRef + /E_L U0 + /V_m U0 + /V_th theta + /V_reset 10.0 % according to Brunel (2000) p 185 + /C_m 1.0 % Yes, capacitance is 1 in the Brunel model + >> SetDefaults + + (Creating the network.) = % show message + + /iaf_psc_alpha [NE] LayoutNetwork /E_net Set + /iaf_psc_alpha [NI] LayoutNetwork /I_net Set + + % some connecting functions need lists (arrays) over all + % neurons they should work on, so we need to extract these + % lists from the subnetworks + + % obtain array with GIDs of all excitatory/inhibitory neurons + /E_neurons E_net GetGlobalNodes def + /I_neurons I_net GetGlobalNodes def + + % list of all neurons + /allNeurons E_neurons I_neurons join def + + (Creating Poisson generators.) = + /poisson_generator + << % set firing rate + /rate p_rate + >> SetDefaults + + /expoisson /poisson_generator Create def + /inpoisson /poisson_generator Create def + + % We could do with only one detector, + % but by recording the populations separately, + % we needn't sort the recordings later + (Creating excitatory spike detector.) = + /exsd /spike_detector Create def + exsd + << + /label (brunel-2-ex-threaded) + /withtime true % record time of spikes + /withgid true % and the global ID of the neuron + /to_file true % write results to a file + /to_memory true % record spikes in memory + >> SetStatus + + (Creating inhibitory spike detector.) = + /insd /spike_detector Create def + insd + << + /label (brunel-2-in-threaded) + /withtime true % record time of spikes + /withgid true % and the global ID of the neuron + /to_file true % write results to a file + /to_memory true % record spikes in memory + >> SetStatus + + % Create custom synapse types with appropriate values for + % our excitatory and inhibitory connections + /static_synapse_hom_wd << /delay delay >> SetDefaults + /static_synapse_hom_wd /syn_ex << /weight JE >> CopyModel + /static_synapse_hom_wd /syn_in << /weight JI >> CopyModel + + (Connecting excitatory neurons.) = + % expoisson E_neurons /syn_ex DivergentConnect + expoisson 1 arraystore E_neurons /all_to_all /syn_ex Connect + + /target_ids E_net GetLocalNodes def + /ns [ target_ids length ] { pop CE } Table def + /empty [ target_ids length ] { pop [] } Table def + /source_ids E_net GetGlobalNodes def + % source_ids target_ids ns empty empty true true /syn_ex RandomConvergentConnect_ia_ia_ia_daa_daa_b_b_l + % E_neurons E_net CE /syn_ex RandomConvergentConnect + E_neurons E_neurons << /rule /fixed_indegree /indegree CE >> /syn_ex Connect + + /ns [ target_ids length ] { pop CI } Table def + /source_ids I_net GetGlobalNodes def + % source_ids target_ids ns empty empty true true /syn_in RandomConvergentConnect_ia_ia_ia_daa_daa_b_b_l + % I_neurons E_net CI /syn_in RandomConvergentConnect + I_neurons E_neurons << /rule /fixed_indegree /indegree CI >> /syn_in Connect + + (Connecting inhibitory population.) = + % inpoisson I_neurons /syn_ex DivergentConnect + inpoisson 1 arraystore I_neurons /all_to_all /syn_ex Connect + + + /target_ids I_net GetLocalNodes def + /ns [ target_ids length ] { pop CE } Table def + /empty [ target_ids length ] { pop [] } Table def + /source_ids E_net GetGlobalNodes def + %source_ids target_ids ns empty empty true true /syn_ex RandomConvergentConnect_ia_ia_ia_daa_daa_b_b_l + %E_neurons I_net CE /syn_ex RandomConvergentConnect + E_neurons I_neurons << /rule /fixed_indegree /indegree CE >> /syn_ex Connect + + + /ns [ target_ids length ] { pop CI } Table def + /source_ids I_net GetGlobalNodes def + % source_ids target_ids ns empty empty true true /syn_in RandomConvergentConnect_ia_ia_ia_daa_daa_b_b_l + % I_neurons I_net CI /syn_in RandomConvergentConnect + I_neurons I_neurons << /rule /fixed_indegree /indegree CI >> /syn_in Connect + + % Spike detectors are connected to the first Nrec neurons in each + % population. Since neurons are equal and connectivity is homogeneously + % randomized, this is equivalent to picking Nrec neurons at random + % from each population + (Connecting spike detectors.) = + + % E_neurons Nrec Take exsd ConvergentConnect % pick the first 500 neurons + % I_neurons Nrec Take insd ConvergentConnect + E_neurons Nrec Take exsd 1 arraystore /all_to_all Connect % pick the first 500 neurons + I_neurons Nrec Take insd 1 arraystore /all_to_all Connect + + toc /BuildCPUTime Set + + /syn_ex GetDefaults /num_connections get /n_ex_syn Set + /syn_in GetDefaults /num_connections get /n_in_syn Set + +%%% SIMULATION SECTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + % run, measure computer time with tic-toc + tic + simtime Simulate + toc /SimCPUTime Set + + % write a little report + (\nBrunel Network Simulation) = + (Number of Threads : ) =only local_num_threads = + (Number of Neurons : ) =only N = + (Number of Synapses: ) =only 0 GetStatus /num_connections get = + ( Excitatory : ) =only n_ex_syn = + ( Inhibitory : ) =only n_in_syn = + (Excitatory rate : ) =only exsd ComputeRate =only ( Hz) = + (Inhibitory rate : ) =only insd ComputeRate =only ( Hz) = + (Building time : ) =only BuildCPUTime =only ( s) = + (Simulation time : ) =only SimCPUTime =only ( s\n) = + diff --git a/examples/nest/brunel-2000_threaded_connect.sli b/examples/nest/brunel-2000_threaded_connect.sli index d91bca4ba5..530f9df2f6 100644 --- a/examples/nest/brunel-2000_threaded_connect.sli +++ b/examples/nest/brunel-2000_threaded_connect.sli @@ -1,22 +1,24 @@ /* - brunel.sli - - Copyright (C) 2004 The NEST Initiative - This file 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 2 of the License, or - (at your option) any later version. - - This file 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, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ + * brunel-2000_threaded_connect.sli + * + * This file is part of NEST. + * + * Copyright (C) 2004 The NEST Initiative + * + * NEST 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 2 of the License, or + * (at your option) any later version. + * + * NEST 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 NEST. If not, see . + * + */ /* Brunel Network @@ -179,7 +181,7 @@ M_WARNING setverbosity % nest --userargs=threads=4 script.sli % % If it is not given, it defaults to 2 -statusdict/userargs :: size +statusdict/userargs :: size 1 geq { 0 get (=) breakup 1 get int /local_num_threads Set } @@ -310,8 +312,8 @@ statusdict/userargs :: size toc /BuildCPUTime Set - /syn_ex GetDefaults /num_connections get /n_ex_syn Set - /syn_in GetDefaults /num_connections get /n_in_syn Set + /syn_ex GetDefaults /num_connections get /n_ex_syn Set + /syn_in GetDefaults /num_connections get /n_in_syn Set %%% SIMULATION SECTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/examples/nest/brunel-sli_connect.sli b/examples/nest/brunel-sli_connect.sli index 17d576c151..5081853e8a 100644 --- a/examples/nest/brunel-sli_connect.sli +++ b/examples/nest/brunel-sli_connect.sli @@ -201,7 +201,7 @@ ComputePSPnorm /J_max_unit Set ResetKernel % clear all existing network elements M_WARNING setverbosity % set resolution and total/local number of threads -[0] +0 << /resolution dt /local_num_threads local_num_threads @@ -226,7 +226,7 @@ M_WARNING setverbosity >> SetDefaults - (SLI only network building) + (SLI only network building) = % Setting neuron default parameters @@ -286,8 +286,6 @@ M_WARNING setverbosity /static_synapse_hom_wd /syn_ex << /weight JE >> CopyModel /static_synapse_hom_wd /syn_in << /weight JI >> CopyModel - synapsedict /syn_ex get /syn_ex_id Set - synapsedict /syn_in get /syn_in_id Set synapsedict /static_synapse get /syn_default Set rngdict /MT19937 get 123456789 CreateRNG /rng Set @@ -386,13 +384,13 @@ M_WARNING setverbosity % Connect Poisson generator to neurons 1 1 E_last { - expoisson exch syn_ex_id Connect_i_i_i + expoisson exch /syn_ex Connect } for % Connect Poisson generator to neurons I_first 1 I_last { - inpoisson exch syn_ex_id Connect_i_i_i + inpoisson exch /syn_ex Connect } for % Spike detectors are connected to the first Nrec neurons in each @@ -403,12 +401,12 @@ M_WARNING setverbosity 1 1 Nrec { - exsd syn_ex_id Connect_i_i_i + exsd /syn_ex Connect } for I_first dup 1 exch Nrec add { - insd syn_ex_id Connect_i_i_i + insd /syn_ex Connect } for (Drawing excitatory connections.) = @@ -423,7 +421,8 @@ M_WARNING setverbosity rng NE irand % draw random number in [0,NE) 1 add % plus 1 to get number in [1,NE] target - syn_ex_id Connect_i_i_i + /syn_ex + Connect } repeat } for @@ -434,7 +433,7 @@ M_WARNING setverbosity CE { rng NE irand 1 add - target syn_ex_id Connect_i_i_i + target /syn_ex Connect } repeat } for @@ -447,7 +446,7 @@ M_WARNING setverbosity CI { rng NI irand I_first add - target syn_in_id Connect_i_i_i + target /syn_in Connect } repeat } for @@ -460,7 +459,7 @@ M_WARNING setverbosity CI { rng NI irand I_first add - target syn_in_id Connect_i_i_i + target /syn_in Connect } repeat } for } bind def @@ -477,13 +476,13 @@ M_WARNING setverbosity % Connect Poisson generator to neurons 1 1 E_last { - expoisson exch syn_ex_id Connect_i_i_i + expoisson exch /syn_ex Connect } for % Connect Poisson generator to neurons I_first 1 I_last { - inpoisson exch syn_ex_id Connect_i_i_i + inpoisson exch /syn_ex Connect } for % Spike detectors are connected to the first Nrec neurons in each @@ -494,12 +493,12 @@ M_WARNING setverbosity 1 1 Nrec { - exsd syn_ex_id Connect_i_i_i + exsd /syn_ex Connect } for I_first dup 1 exch Nrec add { - insd syn_ex_id Connect_i_i_i + insd /syn_ex Connect } for (Drawing excitatory connections.) = @@ -514,7 +513,7 @@ M_WARNING setverbosity rng NE irand_g_i % draw random number in [0,NE) 1 add_ii % plus 1 to get number in [1,NE] target - syn_ex_id Connect_i_i_i + /syn_ex Connect } repeat_ } for @@ -529,7 +528,7 @@ M_WARNING setverbosity CE { rng NE irand_g_i 1 add_ii - target syn_ex_id Connect_i_i_i + target /syn_ex Connect } repeat_ } for @@ -546,7 +545,7 @@ M_WARNING setverbosity CI { rng NI irand_g_i I_first add_ii - target syn_in_id Connect_i_i_i + target /syn_in Connect } repeat_ } for @@ -559,7 +558,7 @@ M_WARNING setverbosity CI { rng NI irand_g_i I_first add_ii - target syn_in_id Connect_i_i_i + target /syn_in Connect } repeat_ } for } bind userdict Inline def diff --git a/examples/nest/brunel-sli_neuron.sli b/examples/nest/brunel-sli_neuron.sli index 932e999877..4da8fdfd69 100644 --- a/examples/nest/brunel-sli_neuron.sli +++ b/examples/nest/brunel-sli_neuron.sli @@ -1,5 +1,5 @@ /* - * brunel.sli + * brunel-sli_neuron.sli * * This file is part of NEST. * @@ -137,7 +137,7 @@ def % number of neurons per population to record from /Nrec 50 def - [0] + 0 << /resolution dt /overwrite_files true @@ -198,7 +198,7 @@ def /calibrate { GetResolution /h Set -} +} def /compile { @@ -245,8 +245,8 @@ end % lists from the subnetworks % obtain array with GIDs of all excitatory/inhibitory neurons - /E_neurons E_net GetNodes def - /I_neurons I_net GetNodes def + /E_neurons E_net GetGlobalNodes def + /I_neurons I_net GetGlobalNodes def % list of all neurons /allNeurons E_neurons I_neurons join def @@ -308,14 +308,14 @@ end CE % number of source neurons to pick /syn_ex % the synapse model RandomConvergentConnect - } bind % bind improves efficiency + } % bind improves efficiency forall E_neurons { I_neurons exch CI /syn_in RandomConvergentConnect - } bind forall + } forall (Connecting inhibitory population.) = @@ -326,12 +326,12 @@ end I_neurons { E_neurons exch CE /syn_ex RandomConvergentConnect - } bind forall + } forall I_neurons { I_neurons exch CI /syn_in RandomConvergentConnect - } bind forall + } forall % Spike detectors are connected to the first Nrec neurons in each % population. Since neurons are equal and connectivity is homogeneously @@ -343,6 +343,8 @@ end I_neurons Nrec Take insd ConvergentConnect toc /BuildCPUTime Set + (Building time : ) =only BuildCPUTime =only ( s) = + /syn_ex GetDefaults /num_connections get /n_ex_syn Set /syn_in GetDefaults /num_connections get /n_in_syn Set diff --git a/examples/nest/music/conttest.py b/examples/nest/music/conttest.py index 2b54ba3a38..f3d1e7ea30 100755 --- a/examples/nest/music/conttest.py +++ b/examples/nest/music/conttest.py @@ -1,4 +1,5 @@ -#!/usr/bin/python +#!/usr/bin/env python +# -*- coding: utf-8 -*- # # conttest.py # @@ -21,6 +22,12 @@ import nest +nest.sli_run("statusdict/have_music ::") +if not nest.spp(): + import sys + print("NEST was not compiled with support for MUSIC, not running.") + sys.exit() + mcip = nest.Create('music_cont_in_proxy') nest.SetStatus(mcip, {'port_name' : 'contdata'}) diff --git a/examples/nest/music/minimalmusicsetup-pynest.music b/examples/nest/music/minimalmusicsetup-pynest.music new file mode 100644 index 0000000000..c424fd6616 --- /dev/null +++ b/examples/nest/music/minimalmusicsetup-pynest.music @@ -0,0 +1,11 @@ +stoptime=0.01 + +[from] + binary=./minimalmusicsetup_sendnest.py + np=1 + +[to] + binary=./minimalmusicsetup_receivenest.py + np=1 + +from.spikes_out -> to.spikes_in [1] diff --git a/examples/nest/music/minimalmusicsetup_receivenest.py b/examples/nest/music/minimalmusicsetup_receivenest.py new file mode 100755 index 0000000000..b4f8ae1cc9 --- /dev/null +++ b/examples/nest/music/minimalmusicsetup_receivenest.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# minimalmusicsetup_receivenest.py +# +# This file is part of NEST. +# +# Copyright (C) 2004 The NEST Initiative +# +# NEST 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 2 of the License, or +# (at your option) any later version. +# +# NEST 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 NEST. If not, see . + +import nest + +nest.sli_run("statusdict/have_music ::") +if not nest.spp(): + import sys + print("NEST was not compiled with support for MUSIC, not running.") + sys.exit() + +nest.set_verbosity("M_ERROR") + +meip = nest.Create ('music_event_in_proxy') +nest.SetStatus (meip, { 'port_name' : 'spikes_in', 'music_channel' : 0 }) + +n = nest.Create ('iaf_neuron') + +nest.Connect (meip, n, { 'weight' : 750.0 }) + +vm = nest.Create ('voltmeter') +nest.SetStatus (vm, { 'to_memory' : False, 'to_screen' : True }) + +nest.Connect (vm, n) + +nest.Simulate (10) diff --git a/examples/nest/music/minimalmusicsetup_receivenest.sli b/examples/nest/music/minimalmusicsetup_receivenest.sli index f7294ffe95..633f9681e3 100644 --- a/examples/nest/music/minimalmusicsetup_receivenest.sli +++ b/examples/nest/music/minimalmusicsetup_receivenest.sli @@ -19,6 +19,9 @@ * along with NEST. If not, see . * */ + +statusdict/have_music :: not {statusdict/exitcodes/success :: quit_i} if + M_ERROR setverbosity /music_event_in_proxy Create /meip Set diff --git a/examples/nest/music/minimalmusicsetup_sendnest.py b/examples/nest/music/minimalmusicsetup_sendnest.py new file mode 100755 index 0000000000..3f394eefe7 --- /dev/null +++ b/examples/nest/music/minimalmusicsetup_sendnest.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# minimalmusicsetup_sendnest.py +# +# This file is part of NEST. +# +# Copyright (C) 2004 The NEST Initiative +# +# NEST 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 2 of the License, or +# (at your option) any later version. +# +# NEST 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 NEST. If not, see . + +import nest + +nest.sli_run("statusdict/have_music ::") +if not nest.spp(): + import sys + print("NEST was not compiled with support for MUSIC, not running.") + sys.exit() + +nest.set_verbosity("M_ERROR") + +sg = nest.Create ('spike_generator') +nest.SetStatus (sg, { 'spike_times' : [1.0, 1.5, 2.0] }) + +n = nest.Create ('iaf_neuron') + +nest.Connect (sg, n, [750.0], [1.0]) + +vm = nest.Create ('voltmeter') +nest.SetStatus (vm, { 'to_memory' : False, 'to_screen' : True }) + +nest.Connect (vm, n) + +meop = nest.Create ('music_event_out_proxy') +nest.SetStatus (meop, { 'port_name' : 'spikes_out' }) + +nest.Connect (sg, meop, { 'music_channel' : 0 }) + +nest.Simulate (10) diff --git a/examples/nest/music/minimalmusicsetup_sendnest.sli b/examples/nest/music/minimalmusicsetup_sendnest.sli index 3c4fe7fc45..0875f67759 100644 --- a/examples/nest/music/minimalmusicsetup_sendnest.sli +++ b/examples/nest/music/minimalmusicsetup_sendnest.sli @@ -19,6 +19,9 @@ * along with NEST. If not, see . * */ + +statusdict/have_music :: not {statusdict/exitcodes/success :: quit_i} if + M_ERROR setverbosity /spike_generator Create /sg Set diff --git a/examples/nest/music/msgtest.py b/examples/nest/music/msgtest.py index e9f6f69ed9..18a6af232e 100755 --- a/examples/nest/music/msgtest.py +++ b/examples/nest/music/msgtest.py @@ -1,4 +1,5 @@ -#!/usr/bin/python +#!/usr/bin/env python +# -*- coding: utf-8 -*- # # msgtest.py # @@ -21,6 +22,12 @@ import nest +nest.sli_run("statusdict/have_music ::") +if not nest.spp(): + import sys + print("NEST was not compiled with support for MUSIC, not running.") + sys.exit() + mmip = nest.Create('music_message_in_proxy') nest.SetStatus(mmip, {'port_name' : 'msgdata'}) diff --git a/examples/nest/music/spike_exporter.sli b/examples/nest/music/spike_exporter.sli index 49fd8c3083..e89a9b9423 100644 --- a/examples/nest/music/spike_exporter.sli +++ b/examples/nest/music/spike_exporter.sli @@ -19,6 +19,9 @@ * along with NEST. If not, see . * */ + +statusdict/have_music :: not {statusdict/exitcodes/success :: quit_i} if + % spike exporter % send spikes generated by a group of spike_generators/parrot_neurons % to a MUSIC port @@ -26,7 +29,7 @@ % data: 2008-10-16 21.0 /T Set % total simulation time -[0] << /resolution 0.1 >> SetStatus +0 << /resolution 0.1 >> SetStatus 10 /N Set % number of spike generators @@ -36,15 +39,15 @@ /subnet Create /SN Set SN ChangeSubnet /parrot_neuron N Create pop -[0] ChangeSubnet -SN GetNodes /parrots Set +0 ChangeSubnet +SN GetGlobalNodes /parrots Set % create N spike generators each to feed one of the N parrots /subnet Create /SNG Set SNG ChangeSubnet /spike_generator N Create pop -[0] ChangeSubnet -SNG GetNodes /generators Set +0 ChangeSubnet +SNG GetGlobalNodes /generators Set % let the spike generator i % produce a spike at 1.0 + 2.0*i ms @@ -87,4 +90,4 @@ cout (rank=) <- Rank <- ( ) <- pop mo GetStatus /index_map get == % simulate -T Simulate \ No newline at end of file +T Simulate diff --git a/examples/nest/music/three_neurons_threaded_receivenest.sli b/examples/nest/music/three_neurons_threaded_receivenest.sli index 7ee4d614e8..317dc97276 100644 --- a/examples/nest/music/three_neurons_threaded_receivenest.sli +++ b/examples/nest/music/three_neurons_threaded_receivenest.sli @@ -19,6 +19,9 @@ * along with NEST. If not, see . * */ + +statusdict/have_music :: not {statusdict/exitcodes/success :: quit_i} if + M_INFO setverbosity 0 << /local_num_threads 2 /overwrite_files true >> SetStatus diff --git a/examples/nest/music/three_neurons_threaded_sendnest.sli b/examples/nest/music/three_neurons_threaded_sendnest.sli index 52ad567ae8..7ba9970a08 100644 --- a/examples/nest/music/three_neurons_threaded_sendnest.sli +++ b/examples/nest/music/three_neurons_threaded_sendnest.sli @@ -19,6 +19,9 @@ * along with NEST. If not, see . * */ + +statusdict/have_music :: not {statusdict/exitcodes/success :: quit_i} if + M_INFO setverbosity 0 << /local_num_threads 2 /overwrite_files true >> SetStatus diff --git a/examples/nest/plot_tsodyks_depr_fac.py b/examples/nest/plot_tsodyks_depr_fac.py index c22c753b99..8e942405f7 100644 --- a/examples/nest/plot_tsodyks_depr_fac.py +++ b/examples/nest/plot_tsodyks_depr_fac.py @@ -1,4 +1,4 @@ -#! /usr/bin/env python +# -*- coding: utf-8 -*- # # plot_tsodyks_depr_fac.py # diff --git a/examples/nest/plot_tsodyks_shortterm_bursts.py b/examples/nest/plot_tsodyks_shortterm_bursts.py index e50c5dcf07..a8770b9619 100644 --- a/examples/nest/plot_tsodyks_shortterm_bursts.py +++ b/examples/nest/plot_tsodyks_shortterm_bursts.py @@ -1,4 +1,4 @@ -#! /usr/bin/env python +# -*- coding: utf-8 -*- # # plot_tsodyks_shortterm_bursts.py # @@ -18,6 +18,7 @@ # # You should have received a copy of the GNU General Public License # along with NEST. If not, see . + import pylab from nest import raster_plot diff --git a/examples/nest/tsodyks2_shortterm_bursts.sli b/examples/nest/tsodyks2_shortterm_bursts.sli index 04f6c2b7ba..196f1f9fd5 100644 --- a/examples/nest/tsodyks2_shortterm_bursts.sli +++ b/examples/nest/tsodyks2_shortterm_bursts.sli @@ -21,9 +21,9 @@ */ /* BeginDocumentation -Name: test_tsodyks_shortterm - sli script for testing Tsodyks short term plastic synapses. +Name: tsodyks2_shortterm_bursts - sli script for testing Tsodyks short term plastic synapses. -Synopsis: (test_tsodyks_shortterm) run +Synopsis: (tsodyks2_shortterm_bursts) run Description: @@ -120,7 +120,7 @@ ResetKernel % clear all existing network elements { userdict begin - [0] ChangeSubnet % return to full network + 0 ChangeSubnet % return to full network /E_net /subnet Create def % create subnet E_net ChangeSubnet % enter subnet @@ -128,7 +128,7 @@ ResetKernel % clear all existing network elements pop % pop gids returned by Create %% obtain array with GIDs of all excitatory neurons - /E_neurons E_net GetNodes def + /E_neurons E_net GetGlobalNodes def /E_params << /tau_m Tau @@ -146,7 +146,7 @@ ResetKernel % clear all existing network elements (Configuring excitatory neuron parameters.) = E_neurons E_params initNeurons - [0] ChangeSubnet % return to full network + 0 ChangeSubnet % return to full network /I_net /subnet Create def % create subnet I_net ChangeSubnet % enter subnet @@ -154,7 +154,7 @@ ResetKernel % clear all existing network elements pop % pop gids returned by Create % obtain array with GIDs of all excitatory neurons - /I_neurons I_net GetNodes def + /I_neurons I_net GetGlobalNodes def /I_params << /tau_m Tau @@ -202,9 +202,9 @@ ResetKernel % clear all existing network elements normal_c << /mu A_mean - /std A_mean 0.5 mul - /min A_mean dup 0.2 mul exch 2.0 mul min - /max A_mean dup 0.2 mul exch 2.0 mul max + /sigma A_mean 0.5 mul abs + /low A_mean dup 0.2 mul exch 2.0 mul min + /high A_mean dup 0.2 mul exch 2.0 mul max >> SetStatus @@ -216,8 +216,8 @@ ResetKernel % clear all existing network elements normal_cl << /mu Tau_rec_mean - /std Tau_rec_mean 0.5 mul - /min Tau_min + /sigma Tau_rec_mean 0.5 mul abs + /low Tau_min >> SetStatus @@ -234,8 +234,8 @@ ResetKernel % clear all existing network elements normal_cl << /mu Tau_fac_mean - /std Tau_fac_mean 0.5 mul - /min Tau_min + /sigma Tau_fac_mean 0.5 mul abs + /low Tau_min >> SetStatus @@ -256,9 +256,9 @@ ResetKernel % clear all existing network elements normal_c << /mu U_mean - /std U_mean 0.5 mul - /min U_min - /max U_max + /sigma U_mean 0.5 mul abs + /low U_min + /high U_max >> SetStatus @@ -306,14 +306,14 @@ ResetKernel % clear all existing network elements /connectNeurons { userdict begin - % Gaussian distribution, mean = 1, std = 1 + % Gaussian distribution, mean = 0, std = 1 myrng rdevdict /normal get CreateRDV /normal_tot Set % Gaussian distribution left/right clipped myrng rdevdict /normal_clipped get CreateRDV /normal_c Set % Gaussian distribution, left clipped - myrng rdevdict /normal_clipped_left get CreateRDV /normal_cl Set + myrng rdevdict /normal_clipped get CreateRDV /normal_cl Set % set options of RandomConvergentConnect to forbid autapses/multapses @@ -326,7 +326,7 @@ ResetKernel % clear all existing network elements % use predefined tsodyks short term plasticity synapse for all % subsequent connections - /Connect << /synapse_model /tsodyks2_synapse >> SetOptions + /Connect << /syn_spec << /model /tsodyks2_synapse >> >> SetOptions (Connecting inputs to excitatory neurons.) = @@ -414,7 +414,7 @@ ResetKernel % clear all existing network elements { userdict begin - [0] ChangeSubnet + 0 ChangeSubnet % select standard synapse @@ -433,7 +433,7 @@ ResetKernel % clear all existing network elements >> SetStatus % select the standard synapse model for subsequent connections - /Connect << /synapse_model /static_synapse >> SetOptions + /Connect << /syn_spec << /model /static_synapse >> >> SetOptions % connect all exc neurons to it E_neurons @@ -524,7 +524,7 @@ userdict begin % set resolution and limits on delays % limits must be set BEFORE connecting any elements - [0] + 0 << /resolution h /local_num_threads local_num_threads diff --git a/examples/nest/tsodyks_depressing.sli b/examples/nest/tsodyks_depressing.sli index a0be64acdd..951f353cb5 100644 --- a/examples/nest/tsodyks_depressing.sli +++ b/examples/nest/tsodyks_depressing.sli @@ -70,7 +70,7 @@ userdict begin % set resolution and limits on delays % limits must be set BEFORE connecting any elements - [0] + 0 << /resolution h /local_num_threads local_num_threads diff --git a/examples/nest/tsodyks_facilitating.sli b/examples/nest/tsodyks_facilitating.sli index 179490fc9b..1a2813c8df 100644 --- a/examples/nest/tsodyks_facilitating.sli +++ b/examples/nest/tsodyks_facilitating.sli @@ -21,9 +21,9 @@ */ /* BeginDocumentation -Name: test_iaf - sli script for overall test of iaf_neuron model +Name: tsodyks_facilitating - sli script for overall test of iaf_neuron model -Synopsis: (test_iaf) run -> compare cout with comments in file +Synopsis: (tsodyks_facilitating) run -> compare cout with comments in file Description: @@ -70,7 +70,7 @@ userdict begin % set resolution and limits on delays % limits must be set BEFORE connecting any elements - [0] + 0 << /resolution h /local_num_threads local_num_threads diff --git a/examples/nest/tsodyks_shortterm_bursts.sli b/examples/nest/tsodyks_shortterm_bursts.sli index 6de01b9a8b..eb141840e8 100644 --- a/examples/nest/tsodyks_shortterm_bursts.sli +++ b/examples/nest/tsodyks_shortterm_bursts.sli @@ -21,9 +21,9 @@ */ /* BeginDocumentation -Name: test_tsodyks_shortterm - sli script for testing Tsodyks short term plastic synapses. +Name: tsodyks_shortterm_bursts - sli script for testing Tsodyks short term plastic synapses. -Synopsis: (test_tsodyks_shortterm) run +Synopsis: (tsodyks_shortterm_bursts) run Description: @@ -123,7 +123,7 @@ ResetKernel % clear all existing network elements { userdict begin - [0] ChangeSubnet % return to full network + 0 ChangeSubnet % return to full network /E_net /subnet Create def % create subnet E_net ChangeSubnet % enter subnet @@ -131,7 +131,7 @@ ResetKernel % clear all existing network elements pop % pop gids returned by Create %% obtain array with GIDs of all excitatory neurons - /E_neurons E_net GetNodes def + /E_neurons E_net GetGlobalNodes def /E_params << /tau_m Tau @@ -149,7 +149,7 @@ ResetKernel % clear all existing network elements (Configuring excitatory neuron parameters.) = E_neurons E_params initNeurons - [0] ChangeSubnet % return to full network + 0 ChangeSubnet % return to full network /I_net /subnet Create def % create subnet I_net ChangeSubnet % enter subnet @@ -157,7 +157,7 @@ ResetKernel % clear all existing network elements pop % pop gids returned by Create % obtain array with GIDs of all excitatory neurons - /I_neurons I_net GetNodes def + /I_neurons I_net GetGlobalNodes def /I_params << /tau_m Tau @@ -205,9 +205,9 @@ ResetKernel % clear all existing network elements normal_c << /mu A_mean - /std A_mean 0.5 mul - /min A_mean dup 0.2 mul exch 2.0 mul min - /max A_mean dup 0.2 mul exch 2.0 mul max + /sigma A_mean 0.5 mul abs + /low A_mean dup 0.2 mul exch 2.0 mul min + /high A_mean dup 0.2 mul exch 2.0 mul max >> SetStatus @@ -219,8 +219,8 @@ ResetKernel % clear all existing network elements normal_cl << /mu Tau_rec_mean - /std Tau_rec_mean 0.5 mul - /min Tau_min + /sigma Tau_rec_mean 0.5 mul abs + /low Tau_min >> SetStatus @@ -237,8 +237,8 @@ ResetKernel % clear all existing network elements normal_cl << /mu Tau_fac_mean - /std Tau_fac_mean 0.5 mul - /min Tau_min + /sigma Tau_fac_mean 0.5 mul abs + /low Tau_min >> SetStatus @@ -259,9 +259,9 @@ ResetKernel % clear all existing network elements normal_c << /mu U_mean - /std U_mean 0.5 mul - /min U_min - /max U_max + /sigma U_mean 0.5 mul abs + /low U_min + /high U_max >> SetStatus @@ -309,14 +309,14 @@ ResetKernel % clear all existing network elements /connectNeurons { userdict begin - % Gaussian distribution, mean = 1, std = 1 + % Gaussian distribution, mean = 0, std = 1 myrng rdevdict /normal get CreateRDV /normal_tot Set % Gaussian distribution left/right clipped myrng rdevdict /normal_clipped get CreateRDV /normal_c Set % Gaussian distribution, left clipped - myrng rdevdict /normal_clipped_left get CreateRDV /normal_cl Set + myrng rdevdict /normal_clipped get CreateRDV /normal_cl Set % set options of RandomConvergentConnect to forbid autapses/multapses @@ -329,7 +329,7 @@ ResetKernel % clear all existing network elements % use predefined tsodyks short term plasticity synapse for all % subsequent connections - /Connect << /synapse_model /tsodyks_synapse >> SetOptions + /Connect << /syn_spec << /model /tsodyks_synapse >> >> SetOptions (Connecting inputs to excitatory neurons.) = @@ -417,7 +417,7 @@ ResetKernel % clear all existing network elements { userdict begin - [0] ChangeSubnet + 0 ChangeSubnet % select standard synapse @@ -430,12 +430,12 @@ ResetKernel % clear all existing network elements sd << /withtime true % record time of spikes - /withpath true % record which neuron spiked + /withgid true % record which neuron spiked /to_file true % write results to a file >> SetStatus % select the standard synapse model for subsequent connections - /Connect << /synapse_model /static_synapse >> SetOptions + /Connect << /syn_spec << /model /static_synapse >> >> SetOptions % connect all exc neurons to it E_neurons @@ -526,7 +526,7 @@ userdict begin % set resolution and limits on delays % limits must be set BEFORE connecting any elements - [0] + 0 << /resolution h /local_num_threads local_num_threads diff --git a/pynest/nest/neuronview.glade b/examples/neuronview/neuronview.glade similarity index 100% rename from pynest/nest/neuronview.glade rename to examples/neuronview/neuronview.glade diff --git a/pynest/nest/neuronview.py b/examples/neuronview/neuronview.py similarity index 92% rename from pynest/nest/neuronview.py rename to examples/neuronview/neuronview.py index 6bc3ffb902..a85a82c607 100644 --- a/pynest/nest/neuronview.py +++ b/examples/neuronview/neuronview.py @@ -1,4 +1,4 @@ -#! /usr/bin/env python +# -*- coding: utf-8 -*- # # neuronview.py # @@ -28,10 +28,8 @@ from matplotlib.figure import Figure from matplotlib.backends.backend_gtkagg import FigureCanvasGTKAgg as FigureCanvas import matplotlib.gridspec as gridspec -from numpy import arange, sin, pi import os - import nest @@ -82,8 +80,8 @@ def update_figure(self, spikes, potentials): self._figure.clear() - num_figures = (len(spikes) != 0) + (len(potentials) != 0) - fig_num = 1 +# num_figures = (len(spikes) != 0) + (len(potentials) != 0) +# fig_num = 1 gs = gridspec.GridSpec(2, 1, height_ratios=[1, 4]) @@ -104,11 +102,14 @@ def update_figure(self, spikes, potentials): def filter_statusdict(self, params): - for key in ["vp", "thread", "type", "state", "model", "local", "frozen", - "origin", "instantiations", "elementsize", "capacity", "available", - "archiver_length", "recordables", "type_id", "t_spike", "tspike", - "tlast", "rmax", "receptor_types", "is_refractory", "refractory_input", - "offset", "ymod"]: + for key in ["archiver_length", "available", "capacity", + "elementsize", "frozen", "global_id", + "instantiations", "is_refractory", "local", + "model", "node_type", "offset", "origin", + "receptor_types", "recordables", + "refractory_input", "rmax", "state", "t_spike", + "thread", "tlast", "tspike", "type_id", "vp", + "ymod"]: if key in params.keys(): params.pop(key) @@ -131,7 +132,7 @@ def populate_comboboxes(self): for entry in models: try: - entrytype = nest.GetDefaults(entry)["type"] + entrytype = nest.GetDefaults(entry)["node_type"] except: entrytype = "unknown" @@ -294,7 +295,7 @@ def repopulate(self) : pos = model.insert_after(None, None) - data = {"key" : key, "type" : type(self.params[key])} + data = {"key" : key, "node_type" : type(self.params[key])} model.set_value(pos, 0, data) model.set_value(pos, 1, str(key)) model.set_value(pos, 2, str(self.params[key])) @@ -309,7 +310,7 @@ def check_value(self, widget, path, new_text) : try : - typename = data["type"].__name__ + typename = data["node_type"].__name__ new_value = eval("%s('%s')" % (typename, new_text)) if typename == "bool" and new_text.lower() in ["false", "0"] : new_value = False diff --git a/extras/ConnPlotter/ConnPlotter.py b/extras/ConnPlotter/ConnPlotter.py index 6b2b0bac47..90fbc99969 100644 --- a/extras/ConnPlotter/ConnPlotter.py +++ b/extras/ConnPlotter/ConnPlotter.py @@ -1,21 +1,25 @@ -# ConnPlotter --- A Tool to Generate Connectivity Pattern Matrices +# -*- coding: utf-8 -*- +# +# ConnPlotter.py # -# This file is part of ConnPlotter. +# This file is part of NEST. # -# Copyright (C) 2009 Hans Ekkehard Plesser/UMB +# Copyright (C) 2004 The NEST Initiative # -# ConnPlotter is free software: you can redistribute it and/or modify +# NEST 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 2 of the License, or # (at your option) any later version. # -# ConnPlotter is distributed in the hope that it will be useful, +# NEST 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 ConnPlotter. If not, see . +# along with NEST. If not, see . + +# ConnPlotter --- A Tool to Generate Connectivity Pattern Matrices """ ConnPlotter is a tool to create connectivity pattern tables. @@ -143,8 +147,8 @@ # - makes no sense to aggregate any longer """ -__version__ = '$Revision: 546 $' -__date__ = '$Date: 2010-06-30 16:36:33 +0200 (Wed, 30 Jun 2010) $' +#__version__ = '$Revision: 546 $' +#__date__ = '$Date: 2010-06-30 16:36:33 +0200 (Wed, 30 Jun 2010) $' __author__ = 'Hans Ekkehard Plesser' __all__ = ['ConnectionPattern', 'SynType', 'plotParams', 'PlotParams'] @@ -164,12 +168,7 @@ # ---------------------------------------------------------------------------- -# The next is a hack that helps me during development (allows run ConnPlotter), -# should find a better solution. -if __name__ == "__main__": - import colormaps as cm -else: - from . import colormaps as cm +from . import colormaps as cm import matplotlib.pyplot as plt import matplotlib as mpl @@ -671,7 +670,7 @@ def __init__(self, conninfo, layers, synapses, intensity, tcd, Vmem): cdict = conninfo[2] if 'sources' in cdict: - if cdict['sources'].keys() == ['model']: + if tuple(cdict['sources'].keys()) == ('model', ): self.snrn = cdict['sources']['model'] else: raise ValueError('Can only handle sources in form {"model": ...}') @@ -679,7 +678,7 @@ def __init__(self, conninfo, layers, synapses, intensity, tcd, Vmem): self.snrn = None if 'targets' in cdict: - if cdict['targets'].keys() == ['model']: + if tuple(cdict['targets'].keys()) == ('model', ): self.tnrn = cdict['targets']['model'] else: raise ValueError('Can only handle targets in form {"model": ...}') @@ -1087,11 +1086,11 @@ def _prepareAxes(self, mode, showLegend): # NB: We must create also those block.newElement() that are not # registered later, since block would otherwise not skip # over the unused location. - for r in xrange(nsynrows): + for r in range(nsynrows): block.newRow(synsep, popsep/2.) - for c in xrange(nsyncols): + for c in range(nsyncols): p = block.newElement(synsep, popsep/2., size=patchsize) - smod = [k for k,s in self._synAttr.iteritems() + smod = [k for k,s in self._synAttr.items() if s.r == r and s.c == c] if smod: assert(len(smod)==1) @@ -1124,7 +1123,7 @@ def _prepareAxes(self, mode, showLegend): if c.matches(sl.name, sp, tl.name, tp)]) # create all synapse patches - for n in xrange(nsyncols): + for n in range(nsyncols): # Do not duplicate existing axes. if (sl.name,sp,tl.name,tp,n) in axset: @@ -1172,7 +1171,7 @@ def _prepareAxes(self, mode, showLegend): # we need to get the synapse names in ascending order of synapse indices snames = [s[0] for s in - sorted([(k,v) for k,v in self._synAttr.iteritems()], + sorted([(k,v) for k,v in self._synAttr.items()], key=lambda kv: kv[1].index) ] snum = len(snames) @@ -1206,7 +1205,7 @@ def _prepareAxes(self, mode, showLegend): cblift = 0.7 * cbmargin self._cbPatches = {} - for j in xrange(snum): + for j in range(snum): self._cbPatches[snames[j]] = \ self._Patch(self._axes.tl[0] + offset + j * (lstep + lwidth), self._axes.lr[1] - cblift, @@ -1320,7 +1319,7 @@ def __init__(self, lList, cList, synTypes=None, intensity='wp', tcd = None else: assert(mList) - import tcd_nest + from . import tcd_nest tcd = tcd_nest.TCD(mList) # Build internal representation of connections. @@ -1352,7 +1351,7 @@ def __init__(self, lList, cList, synTypes=None, intensity='wp', # also add any missing populations alphabetically at end # layers are ignored # create alphabetically sorted list of unique population names - popnames = sorted(list(set([p[1] for p in self._pops]))) + popnames = sorted(list(set([p[1] for p in self._pops])), key=lambda x: x if x is not None else "") if poporder: self._poporder = poporder next = max(self._poporder.values()) + 1 # next free sorting index @@ -1649,12 +1648,16 @@ def plot(self, aggrGroups=False, aggrSyns=False, globalColors=False, # Create colorbars at bottom of figure if showLegend: + # FIXME: rewrite the function to avoid comparisons with None! + f_min = float("-inf") if c_min is None else c_min + f_max = float("-inf") if c_max is None else c_max + # Do we have kernel values exceeding the color limits? - if c_min <= kern_min and kern_max <= c_max: + if f_min <= kern_min and kern_max <= f_max: extmode = 'neither' - elif c_min > kern_min and kern_max <= c_max: + elif f_min > kern_min and kern_max <= f_max: extmode = 'min' - elif c_min <= kern_min and kern_max > c_max: + elif f_min <= kern_min and kern_max > f_max: extmode = 'max' else: extmode = 'both' @@ -1931,7 +1934,7 @@ def _weighteval(weight): elif 'gaussian' in weight: w = weight['gaussian']['mean'] else: - raise Exception('Unknown weight type "%s"' % weight.keys()[0]) + raise Exception('Unknown weight type "%s"' % tuple(weight.keys())[0]) if not w: raise Exception('Cannot handle weight.') @@ -1961,7 +1964,7 @@ def _maskeval(x, y, mask): m = np.logical_and(np.logical_and(ll[0] <= x, x <= ur[0]), np.logical_and(ll[1] <= y, y <= ur[1])) else: - raise Exception('Unknown mask type "%s"' % mask.keys()[0]) + raise Exception('Unknown mask type "%s"' % tuple(mask.keys())[0]) return m @@ -1984,7 +1987,7 @@ def _kerneval(x, y, fun): sig = g['sigma'] return p0 * np.exp(-0.5*(x**2+y**2)/sig**2) else: - raise Exception('Unknown kernel "%s"', fun.keys()[0]) + raise Exception('Unknown kernel "%s"', tuple(fun.keys())[0]) # something very wrong raise Exception('Cannot handle kernel.') diff --git a/extras/ConnPlotter/LICENSE.ConnPlotter b/extras/ConnPlotter/LICENSE.ConnPlotter deleted file mode 100644 index d159169d10..0000000000 --- a/extras/ConnPlotter/LICENSE.ConnPlotter +++ /dev/null @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - 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 2 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, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff --git a/extras/ConnPlotter/MANIFEST b/extras/ConnPlotter/MANIFEST index 0608914151..92610772b8 100644 --- a/extras/ConnPlotter/MANIFEST +++ b/extras/ConnPlotter/MANIFEST @@ -1,4 +1,3 @@ -LICENSE ConnPlotter.py __init__.py colormaps.py diff --git a/extras/ConnPlotter/Makefile.am b/extras/ConnPlotter/Makefile.am index d6d60bd81c..95da6c13d0 100644 --- a/extras/ConnPlotter/Makefile.am +++ b/extras/ConnPlotter/Makefile.am @@ -1,40 +1,29 @@ # Automake file for ConnPlotter -defs= @SLI_THREAD_DEFS@ $defs -MAKEFLAGS= @MAKE_FLAGS@ - EXTRA_DIST= setup.py \ doc examples \ colormaps.py \ ConnPlotter.py \ __init__.py \ - LICENSE.ConnPlotter \ MANIFEST \ tcd_nest.py -# 'all' does sometimes miss changes, therefore we 'clean' first -all: clean - cd @PKGSRCDIR@/$(subdir); @PYTHON_EXEC@ setup.py build +if HAVE_PYTHON install-exec-hook: - cd @PKGSRCDIR@/$(subdir); @PYTHON_EXEC@ setup.py install --prefix=$(DESTDIR)@PYNEST_PREFIX@ - if test `echo @PYTHON_VERSION@ | cut -d. -f2` -ge 6; then \ - mkdir -p $(DESTDIR)@PYNEST_PREFIX@/lib/python@PYTHON_VERSION@/dist-packages; \ - cd $(DESTDIR)@PYNEST_PREFIX@/lib/python@PYTHON_VERSION@/dist-packages; \ - ln -f -s ../site-packages/ConnPlotter; \ - cd $(DESTDIR)@PYNEST_PREFIX@/lib/python@PYTHON_VERSION@/dist-packages; \ - ln -f -s ../site-packages/ConnPlotter*.egg-info; \ - fi - -install-data-hook: install-exec - @INSTALL_PROGRAM@ -m 644 @PKGSRCDIR@/$(subdir)/LICENSE.ConnPlotter $(DESTDIR)@PKGDOCDIR@/ - @INSTALL_PROGRAM@ -m 755 -d $(DESTDIR)@PKGDOCDIR@/ConnPlotter - @INSTALL_PROGRAM@ -m 644 @PKGSRCDIR@/$(subdir)/doc/connplotter_tutorial.pdf $(DESTDIR)@PKGDOCDIR@/ConnPlotter - -clean: - rm -rf build - -datadir=@PKGDOCDIR@/examples/ConnPlotter - -data_DATA=\ + cd $(srcdir); $(PYTHON) setup.py build --build-base=$(abs_builddir)/build install --prefix=$(DESTDIR)$(prefix) --install-lib=$(DESTDIR)$(pythondir) --install-scripts=$(DESTDIR)$(bindir) --install-data=$(DESTDIR)$(pkgdatadir) + +examplesdir=@PKGDOCDIR@/examples/ConnPlotter + +examples_DATA=\ examples/connplotter_tutorial.py + +tutorialdir=@PKGDOCDIR@/ConnPlotter + +tutorial_DATA=\ + doc/connplotter_tutorial.pdf + +endif + +clean-local: + -rm -rf $(abs_builddir)/build diff --git a/extras/ConnPlotter/__init__.py b/extras/ConnPlotter/__init__.py index 1103a3bba5..fc595d81f5 100644 --- a/extras/ConnPlotter/__init__.py +++ b/extras/ConnPlotter/__init__.py @@ -1,31 +1,32 @@ -# ConnPlotter --- A Tool to Generate Connectivity Pattern Matrices +# -*- coding: utf-8 -*- +# +# __init__.py # -# This file is part of ConnPlotter. +# This file is part of NEST. # -# Copyright (C) 2009 Hans Ekkehard Plesser/UMB +# Copyright (C) 2004 The NEST Initiative # -# ConnPlotter is free software: you can redistribute it and/or modify +# NEST 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 2 of the License, or # (at your option) any later version. # -# ConnPlotter is distributed in the hope that it will be useful, +# NEST 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 ConnPlotter. If not, see . +# along with NEST. If not, see . + +# ConnPlotter --- A Tool to Generate Connectivity Pattern Matrices -from ConnPlotter import * +from .ConnPlotter import * -print \ -""" +print(""" ConnPlotter Copyright (C) 2009 Hans Ekkehard Plesser/UMB ConnPlotter comes with ABSOLUTELY NO WARRANTY. ConnPlotter is free software, and you are welcome to redistribute it -under certain conditions. See GNU Public License v.2 or later for details. -""" - - +under certain conditions. See GNU Public License v2 or later for details. +""") diff --git a/extras/ConnPlotter/colormaps.py b/extras/ConnPlotter/colormaps.py index 6346374411..0074c6d9eb 100644 --- a/extras/ConnPlotter/colormaps.py +++ b/extras/ConnPlotter/colormaps.py @@ -1,21 +1,25 @@ -# ConnPlotter --- A Tool to Generate Connectivity Pattern Matrices +# -*- coding: utf-8 -*- +# +# colormaps.py # -# This file is part of ConnPlotter. +# This file is part of NEST. # -# Copyright (C) 2009 Hans Ekkehard Plesser/UMB +# Copyright (C) 2004 The NEST Initiative # -# ConnPlotter is free software: you can redistribute it and/or modify +# NEST 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 2 of the License, or # (at your option) any later version. # -# ConnPlotter is distributed in the hope that it will be useful, +# NEST 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 ConnPlotter. If not, see . +# along with NEST. If not, see . + +# ConnPlotter --- A Tool to Generate Connectivity Pattern Matrices """ Colormaps for ConnPlotter. @@ -35,8 +39,8 @@ # ---------------------------------------------------------------------------- -__version__ = '$Revision: 503 $' -__date__ = '$Date: 2009-12-02 15:13:42 +0100 (Wed, 02 Dec 2009) $' +#__version__ = '$Revision: 503 $' +#__date__ = '$Date: 2009-12-02 15:13:42 +0100 (Wed, 02 Dec 2009) $' __author__ = 'Hans Ekkehard Plesser' __all__ = ['ZeroCenterNorm', 'make_colormap', 'redblue', 'bluered', 'bad_color'] @@ -187,12 +191,12 @@ def make_colormap(color): # this should be proper unit tests n1 = ZeroCenterNorm() if (n1([-1, -0.5, 0.0, 0.5, 1.0]).data == np.array([0, 0.25, 0.5, 0.75, 1.0])).all(): - print "n1 ok" + print("n1 ok") else: - print "n1 failed." + print("n1 failed.") n2 = ZeroCenterNorm(-1, 2) if (n2([-1, -0.5, 0.0, 1.0, 2.0]).data == np.array([0, 0.25, 0.5, 0.75, 1.0])).all(): - print "n2 ok" + print("n2 ok") else: - print "n2 failed." + print("n2 failed.") diff --git a/extras/ConnPlotter/examples/__init__.py b/extras/ConnPlotter/examples/__init__.py index 84b716bea6..7747983d7a 100644 --- a/extras/ConnPlotter/examples/__init__.py +++ b/extras/ConnPlotter/examples/__init__.py @@ -1,26 +1,28 @@ -# ConnPlotter --- A Tool to Generate Connectivity Pattern Matrices +# -*- coding: utf-8 -*- +# +# __init__.py # -# This file is part of ConnPlotter. +# This file is part of NEST. # -# Copyright (C) 2009 Hans Ekkehard Plesser/UMB +# Copyright (C) 2004 The NEST Initiative # -# ConnPlotter is free software: you can redistribute it and/or modify +# NEST 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 2 of the License, or # (at your option) any later version. # -# ConnPlotter is distributed in the hope that it will be useful, +# NEST 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 ConnPlotter. If not, see . - -__all__ = ['simple', 'complex', 'non_dale'] +# along with NEST. If not, see . -from simple import * -from complex import * -from non_dale import * +# ConnPlotter --- A Tool to Generate Connectivity Pattern Matrices +__all__ = ['simple', 'complex', 'non_dale'] +from .simple import * +from .complex import * +from .non_dale import * diff --git a/extras/ConnPlotter/examples/complex.py b/extras/ConnPlotter/examples/complex.py index 57ceb01ac3..71273f1e7e 100644 --- a/extras/ConnPlotter/examples/complex.py +++ b/extras/ConnPlotter/examples/complex.py @@ -1,21 +1,25 @@ -# ConnPlotter --- A Tool to Generate Connectivity Pattern Matrices +# -*- coding: utf-8 -*- +# +# complex.py # -# This file is part of ConnPlotter. +# This file is part of NEST. # -# Copyright (C) 2009 Hans Ekkehard Plesser/UMB +# Copyright (C) 2004 The NEST Initiative # -# ConnPlotter is free software: you can redistribute it and/or modify +# NEST 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 2 of the License, or # (at your option) any later version. # -# ConnPlotter is distributed in the hope that it will be useful, +# NEST 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 ConnPlotter. If not, see . +# along with NEST. If not, see . + +# ConnPlotter --- A Tool to Generate Connectivity Pattern Matrices """ More complex example model. diff --git a/extras/ConnPlotter/examples/connplotter_tutorial.py b/extras/ConnPlotter/examples/connplotter_tutorial.py index 4d1aacdbc1..616ef286dd 100644 --- a/extras/ConnPlotter/examples/connplotter_tutorial.py +++ b/extras/ConnPlotter/examples/connplotter_tutorial.py @@ -1,3 +1,24 @@ +# -*- coding: utf-8 -*- +# +# connplotter_tutorial.py +# +# This file is part of NEST. +# +# Copyright (C) 2004 The NEST Initiative +# +# NEST 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 2 of the License, or +# (at your option) any later version. +# +# NEST 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 NEST. If not, see . + #!======================== #! ConnPlotter: A Tutorial #!======================== @@ -211,7 +232,7 @@ def showTextTable(connPattern, fileTrunk): #! Create layers, store layer info in Python variable for layer in s_layer: - exec '%s = topo.CreateLayer(layer[1])' % layer[0] + exec('%s = topo.CreateLayer(layer[1])' % layer[0]) #! Create connections, need to insert variable names for conn in s_conn: @@ -227,7 +248,7 @@ def showTextTable(connPattern, fileTrunk): #! The following block of messy and makeshift code plots the targets of the #! center neuron of the B/E population in the B/E and the B/I populations. B_top = nest.GetStatus(RG, 'topology')[0] -ctr_id = topo.GetElement(RG, [B_top['rows']/2, B_top['columns']/2]) +ctr_id = topo.GetElement(RG, [int(B_top['rows']/2), int(B_top['columns']/2)]) # find excitatory element in B E_id = [gid for gid in ctr_id @@ -239,8 +260,8 @@ def showTextTable(connPattern, fileTrunk): Itgts = [t for t in alltgts if nest.GetStatus([t], 'model')[0] == 'I'] # obtain positions of targets -Etpos = zip(*topo.GetPosition(Etgts)) -Itpos = zip(*topo.GetPosition(Itgts)) +Etpos = tuple(zip(*topo.GetPosition(Etgts))) +Itpos = tuple(zip(*topo.GetPosition(Itgts))) # plot excitatory pylab.clf() @@ -613,8 +634,8 @@ def showTextTable(connPattern, fileTrunk): #! If not using pyreport, we finally show and block if not using_pyreport: - print - print "The connplotter_tutorial script is done. Call pylab.show() and enjoy the figures!" - print "You may need to close all figures manually to get the Python prompt back." - print + print("") + print("The connplotter_tutorial script is done. Call pylab.show() and enjoy the figures!") + print("You may need to close all figures manually to get the Python prompt back.") + print("") pylab.show = pylab_show diff --git a/extras/ConnPlotter/examples/non_dale.py b/extras/ConnPlotter/examples/non_dale.py index 86289798b2..082ce2ed80 100644 --- a/extras/ConnPlotter/examples/non_dale.py +++ b/extras/ConnPlotter/examples/non_dale.py @@ -1,21 +1,25 @@ -# ConnPlotter --- A Tool to Generate Connectivity Pattern Matrices +# -*- coding: utf-8 -*- +# +# non_dale.py # -# This file is part of ConnPlotter. +# This file is part of NEST. # -# Copyright (C) 2009 Hans Ekkehard Plesser/UMB +# Copyright (C) 2004 The NEST Initiative # -# ConnPlotter is free software: you can redistribute it and/or modify +# NEST 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 2 of the License, or # (at your option) any later version. # -# ConnPlotter is distributed in the hope that it will be useful, +# NEST 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 ConnPlotter. If not, see . +# along with NEST. If not, see . + +# ConnPlotter --- A Tool to Generate Connectivity Pattern Matrices """ Non-Dale example model. diff --git a/extras/ConnPlotter/examples/simple.py b/extras/ConnPlotter/examples/simple.py index 6bb125dcd4..8ff172431e 100644 --- a/extras/ConnPlotter/examples/simple.py +++ b/extras/ConnPlotter/examples/simple.py @@ -1,21 +1,25 @@ -# ConnPlotter --- A Tool to Generate Connectivity Pattern Matrices +# -*- coding: utf-8 -*- +# +# simple.py # -# This file is part of ConnPlotter. +# This file is part of NEST. # -# Copyright (C) 2009 Hans Ekkehard Plesser/UMB +# Copyright (C) 2004 The NEST Initiative # -# ConnPlotter is free software: you can redistribute it and/or modify +# NEST 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 2 of the License, or # (at your option) any later version. # -# ConnPlotter is distributed in the hope that it will be useful, +# NEST 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 ConnPlotter. If not, see . +# along with NEST. If not, see . + +# ConnPlotter --- A Tool to Generate Connectivity Pattern Matrices """ Simple example model. diff --git a/extras/ConnPlotter/setup.py b/extras/ConnPlotter/setup.py index cd11eefc11..f70ae0a929 100644 --- a/extras/ConnPlotter/setup.py +++ b/extras/ConnPlotter/setup.py @@ -1,21 +1,25 @@ -# ConnPlotter --- A Tool to Generate Connectivity Pattern Matrices +# -*- coding: utf-8 -*- +# +# setup.py # -# This file is part of ConnPlotter. +# This file is part of NEST. # -# Copyright (C) 2009 Hans Ekkehard Plesser/UMB +# Copyright (C) 2004 The NEST Initiative # -# ConnPlotter is free software: you can redistribute it and/or modify +# NEST 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 2 of the License, or # (at your option) any later version. # -# ConnPlotter is distributed in the hope that it will be useful, +# NEST 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 ConnPlotter. If not, see . +# along with NEST. If not, see . + +# ConnPlotter --- A Tool to Generate Connectivity Pattern Matrices from distutils.core import setup @@ -25,7 +29,7 @@ author = 'Hans Ekkehard Plesser (Idea: Eilen Nordlie)', author_email= 'hans.ekkehard.plesser@umb.no', url = 'http://www.nest-initiative.org', - license = 'GNU Public License v. 2 or later', + license = 'GNU Public License v2 or later', packages = ['ConnPlotter', 'ConnPlotter.examples'], package_dir = {'ConnPlotter': ''} ) diff --git a/extras/ConnPlotter/tcd_nest.py b/extras/ConnPlotter/tcd_nest.py index 22acdcc9d5..abc83609b5 100644 --- a/extras/ConnPlotter/tcd_nest.py +++ b/extras/ConnPlotter/tcd_nest.py @@ -1,21 +1,25 @@ -# ConnPlotter --- A Tool to Generate Connectivity Pattern Matrices +# -*- coding: utf-8 -*- +# +# tcd_nest.py # -# This file is part of ConnPlotter. +# This file is part of NEST. # -# Copyright (C) 2009 Hans Ekkehard Plesser/UMB +# Copyright (C) 2004 The NEST Initiative # -# ConnPlotter is free software: you can redistribute it and/or modify +# NEST 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 2 of the License, or # (at your option) any later version. # -# ConnPlotter is distributed in the hope that it will be useful, +# NEST 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 ConnPlotter. If not, see . +# along with NEST. If not, see . + +# ConnPlotter --- A Tool to Generate Connectivity Pattern Matrices """ Interface routines to extract synapse information from NEST. @@ -33,8 +37,8 @@ # ---------------------------------------------------------------------------- -__version__ = '$Revision: 445 $' -__date__ = '$Date: 2009-11-11 15:27:13 +0100 (Wed, 11 Nov 2009) $' +#__version__ = '$Revision: 445 $' +#__date__ = '$Date: 2009-11-11 15:27:13 +0100 (Wed, 11 Nov 2009) $' __author__ = 'Hans Ekkehard Plesser' __all__ = ['TCD_NEST'] diff --git a/extras/automake-pre-1.14-fix.patch b/extras/automake-pre-1.14-fix.patch new file mode 100644 index 0000000000..a425f33497 --- /dev/null +++ b/extras/automake-pre-1.14-fix.patch @@ -0,0 +1,11 @@ +--- configure.ac 2013-08-14 22:33:03.000000000 +0200 ++++ configure.ac.in.pre_am114 2013-08-14 22:58:01.000000000 +0200 +@@ -41,7 +41,7 @@ + # We might consider switching to tar-pax (2001) in the future, for now + # tar-ustar (1988) is probably good enough. tar-v7 is not an option, since + # we already hit the 99 char filename limit. +-AM_INIT_AUTOMAKE([tar-ustar subdir-objects]) ++AM_INIT_AUTOMAKE([tar-ustar]) + + # Allow to build NEST using silent rules. + m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES]) diff --git a/extras/emacs/postscript-sli.el b/extras/emacs/postscript-sli.el index 5c82b047d0..8dab533931 100644 --- a/extras/emacs/postscript-sli.el +++ b/extras/emacs/postscript-sli.el @@ -304,7 +304,6 @@ Added search for 'using/endusing', Kupper, 6-aug-2003." ("\\<\\(forall\\|forallindexed\\)\\>" . font-lock-keyword-face) ("\\<\\(Map\\|MapIndexed\\|MapThread\\)\\>" . font-lock-keyword-face) ("\\<\\(begin\\|end\\|namespace\\|using\\|endusing\\)\\>" . font-lock-keyword-face) - ("\\<\\(provide\\|provide-component\\|require\\|require-component\\)\\>" . font-lock-keyword-face) ("\\<\\(stop\\|stopped\\|raiseerror\\|raiseagain\\)\\>" . font-lock-keyword-face) ;; ("[{}]" . font-lock-keyword-face) ; fontify braces ("\\/\\([:.?A-Za-z0-9_]\\)+\\b" . font-lock-function-name-face) ; literal names diff --git a/lib/Makefile.am b/lib/Makefile.am index 3710b444dc..429c27252b 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -1,6 +1,6 @@ nobase_pkgdata_DATA=\ sli/FormattedIO.sli\ - sli/arr.sli\ + sli/arraylib.sli\ sli/debug.sli\ sli/helpinit.sli\ sli/install-help.sli\ @@ -14,7 +14,6 @@ nobase_pkgdata_DATA=\ sli/regexp.sli\ sli/sli-init.sli\ sli/typeinit.sli\ - sli/version.sli\ sli/nest-init.sli\ sli/unittest.sli\ sli/filesystem.sli diff --git a/lib/sli/arr.sli b/lib/sli/arraylib.sli similarity index 91% rename from lib/sli/arr.sli rename to lib/sli/arraylib.sli index 5c9f27f5d2..b451d7126a 100644 --- a/lib/sli/arr.sli +++ b/lib/sli/arraylib.sli @@ -1,5 +1,5 @@ /* - * arr.sli + * arraylib.sli * * This file is part of NEST. * @@ -28,16 +28,12 @@ M-O Gewaltig */ - -/arr ($Revision: 9952 $) provide - - -/arr namespace +/arraylib namespace %---------------------------------------------------------------------------- /* BeginDocumentation -Name: arr::Sum - Return sum of the elements in array. +Name: arraylib::Sum - Return sum of the elements in array. Synopsis: [array] Sum -> number @@ -60,9 +56,9 @@ Remarks: The array must contain no other elements than numbers. The return type (integer or double) depends on the type of elements. -Availability: library "arr" +Availability: library "arraylib" -SeeAlso: arr::Product, arr::Mean, arr::SDev, arr::Var +SeeAlso: arraylib::Product, arraylib::Mean, arraylib::SDev, arraylib::Var */ /Sum[/arraytype] @@ -72,7 +68,7 @@ SeeAlso: arr::Product, arr::Mean, arr::SDev, arr::Var %---------------------------------------------------------------------------- /* BeginDocumentation -Name: arr::Product - Return product of the elements in array. +Name: arraylib::Product - Return product of the elements in array. Synopsis: [array] Product -> number @@ -95,9 +91,9 @@ Remarks: The array must contain no other elements than numbers. The return type (integer or double) depends on the type of elements. -Availability: library "arr" +Availability: library "arraylib" -SeeAlso: arr::Sum, arr::Mean, arr::SDev, arr::Var +SeeAlso: arraylib::Sum, arraylib::Mean, arraylib::SDev, arraylib::Var */ /Product[/arraytype] @@ -108,7 +104,7 @@ SeeAlso: arr::Sum, arr::Mean, arr::SDev, arr::Var %---------------------------------------------------------------------------- /* BeginDocumentation -Name: arr::Mean - Return mean of the elements in array. +Name: arraylib::Mean - Return mean of the elements in array. Synopsis: [array] Mean -> number @@ -130,9 +126,9 @@ Remarks: The array must contain no other elements than numbers. The return type is always double. -Availability: library "arr" +Availability: library "arraylib" -SeeAlso: arr::Product, arr::Sum, arr::SDev, arr::Var +SeeAlso: arraylib::Product, arraylib::Sum, arraylib::SDev, arraylib::Var */ /Mean[/arraytype] @@ -146,7 +142,7 @@ SeeAlso: arr::Product, arr::Sum, arr::SDev, arr::Var %---------------------------------------------------------------------------- /* BeginDocumentation -Name: arr::Var - Return variance of the elements in array. +Name: arraylib::Var - Return variance of the elements in array. Synopsis: [array] Var -> number @@ -169,9 +165,9 @@ Remarks: The array must contain no other elements than numbers. The return type is always double. -Availability: library "arr" +Availability: library "arraylib" -SeeAlso: arr::Product, arr::Sum, arr::Mean, arr::SDev +SeeAlso: arraylib::Product, arraylib::Sum, arraylib::Mean, arraylib::SDev */ /Var[/arraytype] @@ -188,7 +184,7 @@ SeeAlso: arr::Product, arr::Sum, arr::Mean, arr::SDev %---------------------------------------------------------------------------- /* BeginDocumentation -Name: arr::SDev - Return standard deviation of the elements in array. +Name: arraylib::SDev - Return standard deviation of the elements in array. Synopsis: [array] SDev -> number @@ -210,9 +206,9 @@ Remarks: The array must contain no other elements than numbers. The return type is always double. -Availability: library "arr" +Availability: library "arraylib" -SeeAlso: arr::Product, arr::Sum, arr::Mean, arr::Var +SeeAlso: arraylib::Product, arraylib::Sum, arraylib::Mean, arraylib::Var */ /SDev[/arraytype] @@ -226,7 +222,7 @@ SeeAlso: arr::Product, arr::Sum, arr::Mean, arr::Var %---------------------------------------------------------------------------- /* BeginDocumentation -Name: arr::Reform - Reform the dimensions of a hyperrectengular array +Name: arraylib::Reform - Reform the dimensions of a hyperrectengular array Synopsis: [array] [dim1 dim2 ... dimn] Reform -> [reformedArray] @@ -248,7 +244,7 @@ If the new dimensionality is not consistent with the numer of elements in the array, /RangeCheck is raised. Availability: -"Namespace"-dictionary "arr". +"Namespace"-dictionary "arraylib". Author: Ruediger Kupper @@ -295,7 +291,7 @@ SeeAlso: Dimensions, TensorRank, Flatten %---------------------------------------------------------------------------- /* BeginDocumentation -Name: arr::getdeep - get an element from a nested container (array, dict, ...). +Name: arraylib::getdeep - get an element from a nested container (array, dict, ...). Synopsis: (general form:) @@ -353,7 +349,7 @@ There currently is no "putdeep" command, but this functionality is provided by "put". See discussion thread on the nest developer list from 19-jun-2006. -Availability: library "arr" +Availability: library "arraylib" SeeAlso: put, get, Dimensions */ @@ -367,7 +363,7 @@ SeeAlso: put, get, Dimensions %---------------------------------------------------------------------------- /* BeginDocumentation -Name: arr::EdgeTruncate - Truncate 2-d array indices at array edges +Name: arraylib::EdgeTruncate - Truncate 2-d array indices at array edges Synopsis: [2d-indices] height width EdgeTruncate -> [truncated-2d-indices] @@ -392,7 +388,7 @@ The index array is expected to be a (nested) array of integer values only. Code will break otherwise. Availability: -"Namespace"-dictionary "arr". +"Namespace"-dictionary "arraylib". Author: Ruediger Kupper @@ -401,7 +397,7 @@ FirstVersion: 17.3.2003 Remarks: The index array is expected to be a (nested) array of integer values only. -SeeAlso: arr::EdgeWrap, arr::EdgeClip, area2 +SeeAlso: arraylib::EdgeWrap, arraylib::EdgeClip, area2 */ @@ -458,7 +454,7 @@ SeeAlso: arr::EdgeWrap, arr::EdgeClip, area2 %---------------------------------------------------------------------------- /* BeginDocumentation -Name: arr::EdgeClip - Clip 2-d array indices at array edges +Name: arraylib::EdgeClip - Clip 2-d array indices at array edges Synopsis: [2d-indices] height width EdgeClip -> [clipped-2d-indices] @@ -489,7 +485,7 @@ The index array is expected to be a (nested) array of integer values only. Code will break otherwise. Availability: -"Namespace"-dictionary "arr". +"Namespace"-dictionary "arraylib". Author: Ruediger Kupper @@ -498,7 +494,7 @@ FirstVersion: 17.3.2003 Remarks: The index array is expected to be a (nested) array of integer values only. -SeeAlso: arr::EdgeWrap, arr::EdgeTruncate, area2 +SeeAlso: arraylib::EdgeWrap, arraylib::EdgeTruncate, area2 */ @@ -544,7 +540,7 @@ SeeAlso: arr::EdgeWrap, arr::EdgeTruncate, area2 %---------------------------------------------------------------------------- /* BeginDocumentation -Name: arr::EdgeWrap - Wrap 2-d array indices around edges (toriodal) +Name: arraylib::EdgeWrap - Wrap 2-d array indices around edges (toriodal) Synopsis: [2d-indices] height width EdgeWrap -> [wrapped-2d-indices] @@ -577,7 +573,7 @@ The index array is expected to be a (nested) array of integer values only. Code will break otherwise. Availability: -"Namespace"-dictionary "arr". +"Namespace"-dictionary "arraylib". Author: Ruediger Kupper @@ -586,7 +582,7 @@ FirstVersion: 14.3.2003 (Einstein's birthday) Remarks: The index array is expected to be a (nested) array of integer values only. -SeeAlso: arr::IndexWrap, arr::EdgeTruncate, arr::EdgeClip, area2 +SeeAlso: arraylib::IndexWrap, arraylib::EdgeTruncate, arraylib::EdgeClip, area2 */ @@ -629,7 +625,7 @@ SeeAlso: arr::IndexWrap, arr::EdgeTruncate, arr::EdgeClip, area2 %---------------------------------------------------------------------------- /* BeginDocumentation -Name: arr::IndexWrap - project a cyclic index value onto interval [0,N). +Name: arraylib::IndexWrap - project a cyclic index value onto interval [0,N). Synopsis: index N CyclicValue -> normindex @@ -674,7 +670,7 @@ Examples: 6 3 IndexWrap -> 0 Availability: -"Namespace"-dictionary "arr". +"Namespace"-dictionary "arraylib". Author: Ruediger Kupper @@ -684,7 +680,7 @@ Remarks: This function behaves like Mathematica's Mod function (which is different from the mathematical definition of MOD). -SeeAlso: arr::EdgeWrap, mod, CyclicValue +SeeAlso: arraylib::EdgeWrap, mod, CyclicValue */ /IndexWrap_i_i @@ -715,7 +711,7 @@ SeeAlso: arr::EdgeWrap, mod, CyclicValue /* BeginDocumentation -Name: arr::GaborPatch - Return a two-dimensional array with Gabor function. +Name: arraylib::GaborPatch - Return a two-dimensional array with Gabor function. Synopsis: nrows ncols GaborPatch -> [[] .. []] Parameters: @@ -764,7 +760,7 @@ SeeAlso: gabor_ /GaborPatch [/integertype /integertype] { - /arr::GaborPatch GetOptions + /arraylib::GaborPatch GetOptions begin x_min x_max y_min y_max @@ -776,7 +772,7 @@ SeeAlso: gabor_ %% initialization values correspond to those of the NEST %% gabor_generator device (see file synod2/nest/gabor.cpp). -/arr::GaborPatch +/arraylib::GaborPatch << /x_min -2.0 Pi mul /x_max 2.0 Pi mul @@ -790,7 +786,7 @@ SeeAlso: gabor_ >> Options /* BeginDocumentation -Name: arr::GaussPatch - Return a two-dimensional array with Gauss function. +Name: arraylib::GaussPatch - Return a two-dimensional array with Gauss function. Synopsis: nrows ncols GaussPatch -> [[] .. []] Parameters: @@ -840,7 +836,7 @@ SeeAlso: gauss2d_ /GaussPatch [/integertype /integertype] { - /arr::GaussPatch GetOptions + /arraylib::GaussPatch GetOptions begin x_min x_max y_min y_max @@ -863,7 +859,7 @@ SeeAlso: gauss2d_ } def -/arr::GaussPatch +/arraylib::GaussPatch << /x_min -3.0 /x_max 3.0 @@ -878,7 +874,4 @@ SeeAlso: gauss2d_ >> Options -end % namespace arr - - -%% NOTE: There must be a carriage return after the last line, i.e., here: +end % namespace arraylib diff --git a/lib/sli/filesystem.sli b/lib/sli/filesystem.sli index fcc6945a08..8e1c65b795 100644 --- a/lib/sli/filesystem.sli +++ b/lib/sli/filesystem.sli @@ -20,10 +20,6 @@ * */ -/filesystem /SLI ($Revision: 9979 $) provide-component -/filesystem /C++ (7610) require-component - - /FileNames_s { regcomp diff --git a/lib/sli/helpinit.sli b/lib/sli/helpinit.sli index 426c790b78..5f9bc8d23a 100644 --- a/lib/sli/helpinit.sli +++ b/lib/sli/helpinit.sli @@ -1497,13 +1497,22 @@ The algorithm of function validate is as follows: % construct target path for test files % - f (nest/help) search - pop /base Set pop pop - base (nest/unittests/) join cf join /tf Set + + %% this code writes directly into the unittests directory + % f (nest/help) search + % pop /base Set pop pop + % base (nest/unittests/) join cf join /tf Set + + %% this alternative code uses a temporary file + % tmpnam (.sli) join /tf Set + + % tf (w) file /t Set + + %% this alternative code uses a string stream + osstream pop /t Set % write header to test file - tf (w) file /t Set t (true [\n\n) print ; @@ -1540,10 +1549,12 @@ The algorithm of function validate is as follows: % t (] EvaluateLiteralInfixes {and} Fold\n) print ; - t close + %% close new test file and execute + % t close + % tf run - % execute the new test file - tf run + %% alternative version with string stream + t str isstream pop cvx exec } def diff --git a/lib/sli/librandom.sli b/lib/sli/librandom.sli index 2c95c87d73..91ade51b80 100644 --- a/lib/sli/librandom.sli +++ b/lib/sli/librandom.sli @@ -20,10 +20,7 @@ * */ - -/librandom ($Revision: 10100 $) provide -/oosupport (5774) require - +(oosupport) run % added function Random, MD 2006-03-16 % @@ -98,29 +95,40 @@ def /* BeginDocumentation Name:CreateRDV - Create a new random deviate generator + Synopsis: -rngtype rdvfacttype CreateRDV -> rdvtype -rngtype dict1 -> dict2 -Description:Create a new random deviate generator for a given distribution. -See rdevdict for the available distributions, and the documentation for the -individual deviates (under rdevdict::*). The distribution instance can either be -generated from a distribution implemented in C++ represented by rdvfactype or -a SLI implementation of a distribution represented by a dictionary. In the former -case the return value is of rdvtype in the latter case a dictionary. See normal_clipped -for an example on how to define a distribution by a SLI dictionary. -Distribution parameters can be inspected and changed with -GetStatus/SetStatus where applicable. -Parameters:rngtype - random generator as source of random numbers +rngtype rdvfacttype CreateRDV -> rdvtype +rngtype rdvfacttype paramdict CreateRDV -> rdvtype +rngtype dict1 CreateRDV -> dict2 +rngtype dict1 paramdict CreateRDV -> dict2 + +Description: +Create a new random deviate generator for a given distribution. See +rdevdict for the available distributions, and the documentation for +the individual deviates (under rdevdict::*). The distribution instance +can either be generated from a distribution implemented in C++ +represented by rdvfactype or a SLI implementation of a distribution +represented by a dictionary. In the former case the return value is of +rdvtype in the latter case a dictionary. + +If a paramdict is passed, it is used to set the parameters of the +random deviate generator. Parameters can be inspected and changed with +GetStatus/SetStatus where applicable. + +Parameters: +rngtype - random generator as source of random numbers rdvfacttype - distribution to draw from, from rdevdict +paramdict - dictionary with distribution parameters rdvtype - the initialized C++ object representing the distribution dict1 - dictionary used as a template to create the distribution dict2 - the cloned and initalized dictionary representing the distribution -Examples:Create a generator for binomial numbers based on a Knuth LFG random + +Examples: +Create a generator for binomial numbers based on an MT19937 random number generator, set parameters to p=0.2 and n=10, and draw five numbers: SLI ] rngdict /MT19937 get 123456789 CreateRNG /rng Set -SLI ] rng rdevdict /binomial get CreateRDV /bino Set -SLI ] bino << /p 0.2 /n 10 >> SetStatus +SLI ] rng rdevdict /binomial get << /p 0.2 /n 10 >> CreateRDV /bino Set SLI ] bino 5 RandomArray == [2 3 2 2 1] @@ -129,11 +137,12 @@ SeeAlso:rdevdict, rdevdict::normal_clipped, Random, RandomArray, CreateRNG */ /CreateRDV trie [/rngtype /rdvfactorytype] /CreateRDV_g_vf load addtotrie + [/rngtype /rdvfactorytype /dictionarytype] { rollu CreateRDV_g_vf dup rolld SetStatus_v } addtotrie [/rngtype /dictionarytype] {clonedict exch pop dup rollu /init call} addtotrie + [/rngtype /dictionarytype /dictionarytype] { rollu clonedict exch pop dup rollu /init call + rolld SetStatus } addtotrie def - - /*BeginDocumentation Name: seed - Set the seed of a random number generator. Synopsis: rangen int seed -> - @@ -327,179 +336,3 @@ def } bind def - - - -/* BeginDocumentation -Name:rdevdict::normal_clipped - clipped gaussian random number distribution -Synopsis:normal_clipped -> dict -Parameters:normal_clipped does not take any arguments but the default values -can be inspected by - normal_clipped GetStatus info -The parameters of a particular corresponding random number distribution object -created by CreateRDV can be modified as shown below -Description:normal_clipped is defined in rdevdict and returns -a dictionary representing a clipped gaussian random number distribution. -The dictionary can be used to create an instance of a corresponding random -number distribution using CreateRDV as in the example below. Here, it -exploited that dictionaries can be used to implement aspects of object oriented -programming in SLI, see function call for more details. Any random number -distribution specified by a dictionary is required to provide at least to -members: The literal /init provides a procedure taking a random number generator -as an argument. The literal /rand provides a procedure returning a random number. Both -procedures should be called using the standard syntax for call. Usually only the -implementer uses these functions and the user accesses the random number distribution -via general functions like CreateRDV and Random. -Examples: -SLI ] rngdict /MT19937 get 123456789 CreateRNG /rng Set -SLI ] rng rdevdict /normal_clipped get CreateRDV /nc Set -SLI ] nc << /mu 10.0 /std 3.0 /min 1.0 /max 15.0 >> SetStatus -SLI ] nc Random == -1.215086e+01 -Author:Helias, Diesmann -FirstVersion: 2006-06-26 -SeeAlso: Random, CreateRDV, rdevdict::normal_clipped_left, rdevdict::normal_clipped_right, rdevdict, call -*/ -rdevdict -/normal_clipped -<< - /mu 0.0 - /std 1.0 - /min -1.0 - /max 1.0 - - /init - { % This is the constructor used by CreateRDV to create - % an instance of this distribution. The corresponding variant - % of CreateRDV is called with: rng <> CreateRDV and - % uses <> /init call to execute init in the proper - % context. - rdevdict /normal get CreateRDV - /dv Set % not defined in template normal_clipped - - } - - /rand - { - { - dv Random std mul mu add - dup dup - min gt exch - max lt and - { exit } { pop } ifelse - } loop - } ->> cvo put - -/* BeginDocumentation -Name:rdevdict::normal_clipped_left - left clipped gaussian random number distribution -Synopsis:normal_clipped_left -> dict -Parameters:normal_clipped_left does not take any arguments but the default values -can be inspected by - normal_clipped_left GetStatus info -The parameters of a particular corresponding random number distribution object -created by CreateRDV can be modified as shown below -Description:normal_clipped_left is defined in rdevdict and returns -a dictionary representing a left clipped gaussian random number distribution. -The dictionary can be used to create an instance of a corresponding random -number distribution using CreateRDV as in the example below. For more information -on the implementation of random number distributions using dictionaries see -normal_clipped. -Examples: -SLI ] rngdict /MT19937 get 123456789 CreateRNG /rng Set -SLI ] rng rdevdict /normal_clipped_left get CreateRDV /nc Set -SLI ] nc << /mu 10.0 /std 3.0 /min 14.0 >> SetStatus -SLI ] nc Random == -1.549122e+01 -Author:Helias -FirstVersion: 2006-06-27 -SeeAlso: Random, CreateRDV, rdevdict::normal_clipped, rdevdict::normal_clipped_right, rdevdict, call -*/ -rdevdict -/normal_clipped_left -<< - /mu 0.0 - /std 1.0 - /min -1.0 - - /init - { % This is the constructor used by CreateRDV to create - % an instance of this distribution. The corresponding variant - % of CreateRDV is called with: rng <> CreateRDV and - % uses <> /init call to execute init in the proper - % context. - rdevdict /normal get CreateRDV - /dv Set % not defined in template normal_clipped - - } - - /rand - { - { - dv Random std mul mu add - dup - min gt - { exit } { pop } ifelse - } loop - } ->> cvo put - -/* BeginDocumentation -Name:rdevdict::normal_clipped_right - right clipped gaussian random number distribution -Synopsis:normal_clipped_right -> dict -Parameters:normal_clipped_right does not take any arguments but the default values -can be inspected by - normal_clipped_right GetStatus info -The parameters of a particular corresponding random number distribution object -created by CreateRDV can be modified as shown below -Description:normal_clipped_right is defined in rdevdict and returns -a dictionary representing a right clipped gaussian random number distribution. -The dictionary can be used to create an instance of a corresponding random -number distribution using CreateRDV as in the example below. For more information -on the implementation of random number distributions using dictionaries see -normal_clipped. -Examples: -SLI ] rngdict /MT19937 get 123456789 CreateRNG /rng Set -SLI ] rng rdevdict /normal_clipped_right get CreateRDV /nc Set -SLI ] nc << /mu 10.0 /std 3.0 /max 14.0 >> SetStatus -SLI ] nc Random == -4.618916e+00 -Author:Diesmann -FirstVersion: 2008-09-17 -SeeAlso: Random, CreateRDV, rdevdict::normal_clipped, rdevdict::normal_clipped_left, rdevdict, call -*/ -rdevdict -/normal_clipped_right -<< - /mu 0.0 - /std 1.0 - /max -1.0 - - /init - { % This is the constructor used by CreateRDV to create - % an instance of this distribution. The corresponding variant - % of CreateRDV is called with: rng <> CreateRDV and - % uses <> /init call to execute init in the proper - % context. - rdevdict /normal get CreateRDV - /dv Set % not defined in template normal_clipped - - } - - /rand - { - { - dv Random std mul mu add - dup - max lt - { exit } { pop } ifelse - } loop - } ->> cvo put - - - - - - - diff --git a/lib/sli/library.sli b/lib/sli/library.sli index b13af4e869..c5675929c4 100644 --- a/lib/sli/library.sli +++ b/lib/sli/library.sli @@ -20,17 +20,8 @@ * */ -/* - SLI library management initalization - -*/ - - - systemdict begin - - /* BeginDocumentation Name: namespace - Open a namespace @@ -118,7 +109,8 @@ SeeAlso: call, using, endusing begin } ifelse } bind def - + + /* BeginDocumentation Name: using - Make symbols of a namespace or dictionary available in the current scope. @@ -159,7 +151,7 @@ Parameters: Examples: % the following makes the routines of the unittest library available to the current scope: - (unittest) (6688) require + (unittest) run /unittest using ..your code.. endusing @@ -231,6 +223,7 @@ SeeAlso: endusing, namespace, call } bind def + /* BeginDocumentation Name: endusing - Close the scope of a 'using' context. @@ -242,7 +235,7 @@ For further information, see 'using'. Examples: % the following makes the routines of the unittest library available to the current scope: - (unittest) (6688) require + (unittest) run /unittest using ..your code.. endusing @@ -273,6 +266,7 @@ SeeAlso: using, namespace, call } bind def + % ========= Implementation of :: begins here ========= % (sorry, this is a length piece of code) @@ -504,801 +498,6 @@ SeeAlso: namespace, call - - - - -/* BeginDocumentation -Name: libdict - Dictionary of provided libraries and their components. - -Description: -This dictionary is used to implement the functionality of the commands -provide, provide-component, require and require-component. - -The user needs never and should never access this dictionary directly. - -Remarks: -The user needs never and should never access this dictionary directly. - -Author: -Ruediger Kupper - -FirstVersion: -28-Jul-2003 - -Availability: SLI2.0 - -References: -[1] Ruediger Kupper, SLI library management, - HRI-EU Report 06/05, Honda Research Institute Europe GmbH, 2006. - -SeeAlso: provide, provide-component, require, require-component -*/ - /libdict << /__autoloaded_files << >> >> def - - - - - -/* BeginDocumentation -Name: provide-component - State that code provides a subcomponent of a library. - -Synopsis: -/libname /component [version] provide-component -> - -/libname /component (version) provide-component -> - -special case (see below): -/libname /component ($Revision: 9952 $) provide -> - - -Description: -This command is an extended version of "provide". Unless you are a -developer of SLI modules, you will almost certainly want to use the -simpler "provide" command. - -This command will usually be used once in a .sli-File that implements -the SLI part of a multipart SLI library, or in the initilizer string for the -C++ part of a multipart SLI library. There might by additional use-cases. - -This command states that the file it appears in provides the component -/component of the library /libname. The version number specified is -the version of the respective component. - -Use cases: - -The implementation of SLI modules usually consist not only of SLI code, but also of -associated C++-code. Usually, the C++ part is linked into the SLI -executable, and the SLI part is called at interpreter startup to do -additional initialization, type-tries, etc. -The two are seen as two components of one library. -Standard names for the two components are /SLI and /C++. -Each library is required to have at least a /SLI component. - -Normal libraries (e.g., collections of SLI routines for a certain purpose) -have only a /SLI component. Use the simpler "provide" command for -these libraries. For more complex SLI-only libraries, you can use -"provide-component" to give independent version numbers to different -parts of your library (e.g., the user interface), but this is usually -not required. - -Note that for the 'require'/'require-component' command to work -correctly, the SLI file defining a library -must itself be named accordingly: A file containing the command - /libname ... provide-component -shall be named - libname.sli - -Parameters: -/libname - Name of the library. -/component - Name of a component that makes up the library, e.q. /SLI, /C++, etc. -version - Version number of the respective component (string or array of int, - for details on the format of version specifiers, see the - command version::s2v, or the help desk (todo).) - In CVS-controlled files, it is advisable to set this to - '(Revision)'. - -Examples: -/mylibrary /SLI (1.0) provide-component -/mylibrary /FancyUserInterface [23 5] provide-component - -Diagnostics: -If a component of the given name in the given library has already been earlier -provided, /LibraryExistsError is raised, regardless of version number. - -Remarks: -For details on the format of version specifiers, see the help desk (todo). -In CVS-controlled files, it is advisable to set the version argument to -'(Revision)'. - -Note that for the 'require' and 'require-component' commands to work -correctly, the SLI file defining a library -must itself be named accordingly: A SLI file containing the command - /libname ... provide-component -shall be named - libname.sli - -Author: -Ruediger Kupper - -FirstVersion: -28-jul-2003 - -Availability: SLI2.0 - -References: -[1] Ruediger Kupper, SLI library management, - HRI-EU Report 06/05, Honda Research Institute Europe GmbH, 2006. - -SeeAlso: libdict, provide, require, require-component, version::s2v -*/ - /provide-component[/literaltype /literaltype /stringtype] - { - % convert string to version array, then call array variant: - version /s2v call - provide-component - } bind def - - - /provide-component[/literaltype /literaltype /arraytype] - { - %stack: /libname /compname version - % safety check: is version a valid version number array? - dup version /validate call - %stack: /libname /compname version - - % safety-check: - % was a component of this library already provided? - systemdict /libdict get dup - %stack: /libname /compname version <> <> - 4 index known not - {% library is not know, so create it: - %stack: /libname /compname version <> - dup 4 index << >> put - } if - % library is (now) known - %stack: /libname /compname version <> - 3 index get dup - %stack: /libname /compname version <> <> - 3 index known - {% component was already previously defined! - %stack: /libname /compname version <> - begin % libname - %stack: /libname /compname version - M_ERROR (provide-component) - (Component /) 4 index cvs join ( of library ') join 5 index cvs join (' was already provided with version number ) join - 4 index load version /v2s call join - (.) join message - end % libname - /provide-component /LibraryExistsError raiseerror - } if - % end safety check. - % library is (now) known - - %stack: /libname /compname version <> - 2 index 2 index put - %stack: /libname /compname version - M_STATUS (provide-component) (Providing library ') 5 index cvs join (', component /) join 4 index cvs join (, version ) join - 3 index version /v2s call join - (.) join message - 3 npop - } bind def - - -/* BeginDocumentation -Name: provide - State that code provides (the SLI part of) a library. - -Synopsis: -/libname [version] provide -> - -/libname (version) provide -> - -special case (see below): -/libname ($Revision: 9952 $) provide -> - - -Description: -This command will usually be used once in each *.sli file that -implements a library. Use this command for a libraries that are -collections of SLI-routines for a certain purpose. - -This command states that the file it appears in defines provides the -given version of the library /libname. - -Additional information: - -This command states that the file it appears in defines the /SLI -component of the library /libname. The version number specified is -the version of the /SLI component (which for SLI-only libraries can be -thought of as the library version). - -See 'provide-component' for a variant of this command that can be -used for libraries that consist of multiple parts or a mixture of SLI -and C++ code. - -Note that for the 'require' command to work correctly, the library -file itself must be named accordingly: A file containing the command - /libname ... provide -shall be named - libname.sli - -Parameters: -/libname - Name of the library. -version - Version number of the respective component (string or array of int, - for details on the format of version specifiers, see the - command version::s2v, or the help desk (todo).) - In CVS-controlled files, it is advisable to set this to - '(Revision)'. - -Examples: -/mylibrary (1.0) provide -/newlibrary ($Revision: 9952 $) provide - -Diagnostics: -If a component of name /SLI in the given library has already been earlier -provided, /LibraryExistsError is raised, regardless of version number. - -Remarks: -For details on the format of version specifiers, see the help desk (todo). -In CVS-controlled files, it is advisable to set the version argument to -'(Revision)'. - -Author: -Ruediger Kupper - -FirstVersion: -28-jul-2003 - -Availability: SLI2.0 - -References: -[1] Ruediger Kupper, SLI library management, - HRI-EU Report 06/05, Honda Research Institute Europe GmbH, 2006. - -SeeAlso: libdict, provide-component, require, require-component, version::s2v -*/ - /provide[/literaltype /stringtype] - { - % convert string to version array, then call array variant: - version /s2v call - provide - } bind def - - /provide[/literaltype /arraytype] - { - /SLI exch provide-component - } bind def - - - - - -%%%%% -% -% :library-autoload-file -% 1. look if file was already loaded. if yes, return true -% 2. if no, try to find it -% 3. if it exists, execute it and register it. return true -% 4. if it does not exist, return false. -% -% The routine returns true, if the file was (perhaps formerly) loaded. -% It ensures, that each file is loaded only once. -% -%%%% - /:library-autoload-file[/stringtype] - { - % see if the file was already loaded: - %stack: (file) - systemdict /libdict get /__autoloaded_files get - %stack: (file) <<__autoloaded_files>> - 1 index cvlit known - {% the file was already loaded, return true - % stack: (file) - M_DEBUG (:library-autoload-file) (File ) 4 -1 roll join ( was already loaded.) join message - true - } - {% the file was not yet loaded, - % so try to find and run it: - % stack: (file) - M_DEBUG (:library-autoload-file) (Trying to run file ) 3 index join (...) join message - % stack: (file) - dup searchifstream - {% the file was found and already opened, so execute its contents - %stack: (file) ifstream - M_DEBUG (:library-autoload-file) (File found. Executing...) message - cvx exec - %stack: (file) - - % register that the file was loaded: - %stack: (file) - systemdict /libdict get /__autoloaded_files get - %stack: (file) <<__autoloaded_files>> - exch cvlit true put - %stack: - - % return true - true - } - {% the file was not found, return false - %stack: (file) - M_FATAL (:library-autoload-file) (Library or component unknown, and file ') 4 -1 roll join (' was not found!) join message - false - } ifelse - } ifelse - } bind def - - - -%%%% -% :library-knownQ -% -% check if library is known in libdict. -% produce messages according to what happens -% and then return true or false. -% (undocumented) -%%%% - - /:library-knownQ[/literaltype] - { - %stack: /libname - - % check: is the library known? - systemdict /libdict get - %stack: /libname <> - 1 index known - {% library is already known, everything is okay. - %stack: /libname - M_DEBUG (:library-knownQ) (Library ') 4 -1 roll cvs join (' is known.) join message - %stack: - - % return value: - true - %stack: boolean - } - {% library is NOT known. - %stack: /libname - M_DEBUG (:library-knownQ) (Library ') 4 -1 roll cvs join (' is unknown.) join message - %stack: - - % return value: - false - %stack: boolean - } ifelse - %stack: boolean - } bind def - - -%%%% -% :component-knownQ -% -% check if component of a library is known in libdict. -% The library itself must be known (see :library-knownQ). -% produce messages according to what happens -% and then return true or false. -% (undocumented) -%%%% - - /:component-knownQ[/literaltype /literaltype] - { - %stack: /libname /componentname - 1 index 1 index - %stack: /libname /componentname /libname /componentname - - systemdict /libdict get - %stack: /libname /componentname /libname /componentname <> - rolld get - %stack: /libname /componentname /componentname <> - exch known - {% component is known. - %stack: /libname /componentname - M_DEBUG (:component-knownQ) (Library ') 5 -1 roll cvs join (' provides component /) join 4 -1 roll cvs join (.) join message - %stack: - - % return value: - true - %stack: boolean - } - {% library is NOT known. - %stack: /libname /componentname - M_DEBUG (:component-knownQ) (Library ') 5 -1 roll cvs join (' does not provide component /) join 4 -1 roll cvs join (.) join message - %stack: - - % return value: - false - %stack: boolean - } ifelse - %stack: boolean - } bind def - - - -%%%% -% :library-and-component-knownQ -% -% check if a library and a component is known in libdict. -% 1. Check if the library is known. -% 2. If so, check, if the component is known, too. -% produce messages according to what happens -% and then return true or false. -% (undocumented) -%%%% - - /:library-and-component-knownQ[/literaltype /literaltype] - { - %stack: /libname /componentname - 1 index :library-knownQ - {% library is known - % check, if component is known, too - % stack: /libname /componentname - :component-knownQ - %stack: boolean - } - {% library is not known - % stack: /libname /componentname - pop pop - false - %stack: boolean - } ifelse - %stack: boolean - } bind def - - -%%%% -% :require-library-and-component -% -% check if library and component is known in libdict. -% If not, run the file libname.sli and re-check. -% produce messages according to what happens -% and then return true or false. -% (undocumented) -%%%% - /:require-library-and-component[/literaltype /literaltype] - { - %stack: /libname /componentname - 1 index 1 index - %stack: /libname /componentname /libname /componentname - - % check: is the library and component known? - :library-and-component-knownQ - %stack: /libname /componentname boolean - {% library and component are already known, everything is okay. - %stack: /libname /componentname - pop pop - % return value: - true - %stack: boolean - } - {% either the library or the componenet is NOT known, - %so try to find and run the sli file: - %stack: /libname /componentname - 1 index cvs (.sli) join - %stack: /libname /componentname (libname.sli) - :library-autoload-file - %stack: /libname /componentname boolean - % the boolean is true, if the file was now or previously loaded. - % it is false, if the file was not found. - - - {% the file was now or previously loaded - % check again, if the library and component is known: - %stack: /libname /componentname - 1 index 1 index - %stack: /libname /componentname /libname /componentname - :library-and-component-knownQ - % stack: /libname /componentname boolean - {% library was loaded, and now is known, all is okay. - % stack: /libname /componentname - M_DEBUG (:require-library-and-component) (Component was provided. Okay.) message - pop pop - % return value: - true - %stack: boolean - } - {% file was loaded, but library and component is STILL NOT known! - % stack: /libname /componentname - M_FATAL (:require-library-and-component) (Library ') 4 index cvs join (' or its component /) join 4 -1 roll cvs join ( is unknown, and file ') join 4 -1 roll cvs join (.sli) join (' did not provide it!) join message - % stack: - - % return value: - false - } ifelse - %stack: boolean - } - {% the file was not found - %stack: /libname /componentname - M_FATAL (:require-library-and-component) (Library ') 4 index cvs join (' or its component /) join 4 -1 roll cvs join ( is unknown, and file ') join 4 -1 roll cvs join (.sli) join (' was not found!) join message - % stack: - - % return value: - false - %stack: boolean - } ifelse - } ifelse - - %stack: boolean - - } bind def - - -/* BeginDocumentation -Name: require-component - State that code requires a certain subcomponent of a library. - -Synopsis: -/libname /component [version] require-component -> - -/libname /component (version) require-component -> - - -Description: -This command is an extended version of "require". Unless you are a -developer of SLI modules, you will almost certainly want to use the -simpler "require" command. - -This command will usually be used once in each *.sli file that -requires a certain component of a multipart SLI library. - -This command states that the file it appears in requires the component -/component of the library /libname. The version number specified is -the MINIMAL required version of the respective component. - -Use cases: - -The implementation of SLI modules usually consist not only of SLI code, but also of -associated C++-code. Usually, the C++ part is linked into the SLI -executable, and the SLI part is called at interpreter startup to do -additional initialization, type-tries, etc. -The two are seen as two components of one library. -Standard names for the two components are /SLI and /C++. -Each library is required to have at least a /SLI component. - -Normal libraries (e.g., collections of SLI routines for a certain purpose) -have only a /SLI component. Use the simpler "require" command for -these libraries. For more complex SLI-only libraries, you can use -"provide-component"/"require-component" to give independent version -numbers to different parts of your library (e.g., the user -interface), but this is usually not required. - -The command works as follows: - -If the specified component of the specified library has not been -provided up to this point, a file named 'libname.sli' will be run (see -command 'run'). The code contained in this file MUST provide the -specified component of the specified library, using the command -'provide' or 'provide-component'. If not, an error will be raised. - -After possibly running libname.sli, the version number of the -respective component is checked. If the provided version is -smaller than the required version, an error is raised. - -Parameters: -/libname - Name of the library. -/component - Name of a component that makes up the library, e.q. /SLI, /C++, etc. -version - Minimal required version number of the respective component - (string or array of int, for details on the format of version - specifiers, see the help desk (todo).) - -Examples: -/mylibrary /SLI (1.0) require-component -/mylibrary /FancyUserInterface [23 5] require-component - -Diagnostics: -- If the specified component of the specified library has not been provided up to - this point, a file named 'libname.sli' will be run. If this code - does not provide the specified component of the specified library, - /LibraryNotProvidedError will be raised. -- If (possibly after running the file), the specified component of the - specified library has not been provided, /LibraryNotProvidedError will - be raised. -- If (possibly after running the file), the specified component of the - specified library has been provided, but the required version number - is higher than the provided one, /LibraryNotProvidedError will be - raised. - -Remarks: -For the search path for file execution, see 'run'. - -Author: -Ruediger Kupper - -FirstVersion: -28-jul-2003 - -Availability: SLI2.0 - -References: -[1] Ruediger Kupper, SLI library management, - HRI-EU Report 06/05, Honda Research Institute Europe GmbH, 2006. - -SeeAlso: libdict, provide, provide-component, require, run -*/ - /require-component[/literaltype /literaltype /stringtype] - { - % convert string to version array, then call array variant: - version /s2v call - require-component - } bind def - - /require-component[/literaltype /literaltype /arraytype] - { - %stack: /libname /componentname version - % safety check: is version a valid version number array? - dup version /validate call - %stack: /libname /componentname version - - 2 index 2 index - %stack: /libname /componentname version /libname /componentname - - :require-library-and-component - not - { - %stack: /libname /componentname version - /require-component /LibraryNotProvidedError raiseerror - } if - - % if we get here, we know that the library dict exists in libdict, - % and that the required component is known, too. - - % We now have to check if it is the correct version. - - %stack: /libname /componentname version - systemdict /libdict get 3 index get - %stack: /libname /componentname version <> - -% % is a component of the given name provided? -% dup 3 index known not -% {%no, its not provided -% %stack: /libname /componentname version <> -% pop -% M_FATAL (require-component) (A component of name /) 4 index cvs join ( is not provided for library ') join 5 index cvs join ('.) join message -% /require-component /LibraryNotProvidedError raiseerror -% } if -% % yes it is provided - - %stack: /libname /componentname version <> - % is it a recent enough version? - 2 index get dup - %stack: /libname /componentname version presentversion presentversion - rollu - %stack: /libname /componentname presentversion version presentversion - 1 index version /vlt call - {%no, version is too small! - %stack: /libname /componentname presentversion version - M_FATAL (require-component) (Component /) 5 index cvs join ( of library ') join 6 index cvs join (' has version ) join - /version namespace - 4 index v2s join - (, but ) join - 3 index v2s join ( was required.) join message - exch pop - end - /require-component /LibraryNotProvidedError raiseerror - } if - %stack: /libname /componentname presentversion version - 4 npop - } bind def - - -/* BeginDocumentation -Name: require - State that code requires a certain library. - -Synopsis: -/libname [SLIversion] require -> - -/libname (SLIversion) require -> - - -/libname [SLIversion] [C++version] require -> - -/libname (SLIversion) (C++version) require -> - -/libname (SLIversion) [C++version] require -> - -/libname [SLIversion] (C++version) require -> - - -Description: -This command will usually be used once in each *.sli file that -requires a certain library of commands. - -This command states that the file it appears in requires the library -/libname. The version number specified is the MINIMAL required -version. - -Additional information: - -The two first versions given in the Synopsis section state that the -file the command appears in requires the /SLI component of the library -/libname. The version number specified is the MINIMAL required version -of the /SLI component (which, for SLI-only libraries, may be thought -of as the library version). - -The other versions given in the Synopsis section state that the file -the command appears in requires the /SLI and the /C++ component of the -multipart library /libname. (See "require-component" for details on -library components.) The version numbers specified are the MINIMAL -required versions of the /SLI and /C++ components. - -See 'require-component' for a variant of this command that can be -used for libraries that consist of multiple parts or a mixture of SLI -and C++ code. - -The command works as follows: - -If the repective component of the specified library has not been -provided up to this point, a file named 'libname.sli' will be run (see -command 'run'). The code contained in this file MUST provide the -respective component of the specified library, using the command -'provide' or 'provide-component'. If not, an error will be raised. - -After possibly running libname.sli, the version number of the -respective component is checked. If the provided version is -smaller than the required version, an error is raised. - -Parameters: -/libname - Name of the library. -SLIversion - Minimal required version number of the /SLI component. - (string or array of int, for details on the format of version - specifiers, see the help desk (todo).) -C++version - Minimal required version number of the /C++ component. - (string or array of int, for details on the format of version - specifiers, see the help desk (todo).) - -Examples: -/mylibrary (1.0) require - -Diagnostics: -- If the respective component of the specified library has not been - provided up to this point, a file named 'libname.sli' will be run. - If this code does not provide the respective component of the specified - library, /LibraryNotProvidedError will be raised. -- If (possibly after running the file), the respective component of the - specified library has not been provided, /LibraryNotProvidedError will - be raised. -- If (possibly after running the file), the respective component of the - specified library has been provided, but the required version number - is higher than the provided one, /LibraryNotProvidedError will be - raised. - -Remarks: -For the search path for file execution, see 'run'. - -Author: -Ruediger Kupper - -FirstVersion: -28-jul-2003 - -Availability: SLI2.0 - -References: -[1] Ruediger Kupper, SLI library management, - HRI-EU Report 06/05, Honda Research Institute Europe GmbH, 2006. - -SeeAlso: libdict, provide, provide-component, require-component, run -*/ - /require[/literaltype /arraytype /stringtype] - { - % convert string to version array, then call array variant: - version /s2v call - require - } bind def - - /require[/literaltype /stringtype /arraytype] - { - % convert string to version array, then call array variant: - exch version /s2v call exch - require - } bind def - - /require[/literaltype /stringtype /stringtype] - { - % convert string to version array, then call array variant: - /version namespace - s2v - exch s2v exch - end - require - } bind def - - /require[/literaltype /arraytype /arraytype] - { - 2 index 2 index /SLI exch require-component - 2 index 1 index /C++ exch require-component - 3 npop - } bind def - - - - /require[/literaltype /stringtype] - { - % convert string to version array, then call array variant: - version /s2v call - require - } bind def - - /require[/literaltype /arraytype] - { - /SLI exch require-component - } bind def - /* BeginDocumentation Name: initialize_module - Initialize module by executing commandstring diff --git a/lib/sli/mathematica.sli b/lib/sli/mathematica.sli index c0cc3ddf78..9d2f75e3fa 100644 --- a/lib/sli/mathematica.sli +++ b/lib/sli/mathematica.sli @@ -20,23 +20,6 @@ * */ -/* - SLI Interpeter initalization - -*/ - -% **************************************************************** -% * SLI's Mathematica Style functions * -% * --------------------------------- * -% * * -% * * -% * * -% **************************************************************** - -/mathematica /SLI ($Revision: 10098 $) provide-component -/mathematica /C++ (1.55) require-component - - %% Mathematica style global Options /* BeginDocumentation @@ -545,9 +528,17 @@ References: % v a i al rollu % v al a i - [-1] exch 1 add prepend - % v al a [i+1 -1] - Take + 2 copy exch length lt + { + [-1] exch 1 add prepend + % v al a [i+1 -1] + Take + } + { + 2 npop + [] + } ifelse + % v al ar rolld % al ar v @@ -716,14 +707,52 @@ end } def +% a p a +% presently less general than the Mathematica version. +% the level specification is restriced to [n], 130222 MD +/MapAtLevel +{ + 0 get + MapRecursion +} def + +/MapRecursion +{ + % a p i + dup % a p i i + 1 gt % a p i b + { + % a p i + 1 sub % a p i + rolld % p i a + + { + % p i ai + rollu % ai p i + 2 copy % ai p i p i + 5 -1 roll % p i p i ai + rollu % p i ai p i + MapRecursion + } Map + % p i a + rollu % a p i + 2 npop % a + } + {pop Map} + ifelse +} def + + /Map_ /Map load def /Map trie [/arraytype /proceduretype] /Map_ load addtotrie +[/arraytype /proceduretype /arraytype] /MapAtLevel load addtotrie [/iteratortype /proceduretype] /Map_iter load addtotrie [/stringtype /proceduretype] /Map_s load addtotrie def + /* BeginDocumentation Name: MapAt - applies a function to some of the elements of its argument Synopsis: array1 proc array2 MapAt -> array3 @@ -934,7 +963,7 @@ References: Bugs: Author: Gewaltig, Diesmann Remarks: Resembles the function Range of Mathematica - SeeAlso: Map, Table + SeeAlso: LayoutArray, Table, array, zeros, ones, Map */ /Range_ /Range load def @@ -986,7 +1015,7 @@ def Author: Gewaltig Remarks: Resembles the function Table of Mathematica References: - SeeAlso: Map, MapIndexed, Range, forall, forallindexed + SeeAlso: Map, MapIndexed, Range, LayoutArray, array, forall, forallindexed */ /Table_ @@ -1009,10 +1038,10 @@ BeginDocumentation Name: MapIndexed - Apply a function to each element of a list/string Synopsis: - [v0 ... vn] {f} Map -> [ f(0,v0) ... f(n,vn) ] + [v1 ... vn] {f} MapIndexed -> [ f(v1,1) ... f(vn,n) ] Parameters: - [v0 ... vn] - list of n+1 arbitrary objects or string. + [v1 ... vn] - list of n arbitrary objects or string. {f} - function of two arguments and one return value. @@ -1022,7 +1051,9 @@ BeginDocumentation the element with the result of f. MapIndexed works similar to Map, however, in adition to the element its index within the array is also passed to the function. - Note that the index starts with 0, according to PostScript convention. + Note that the index starts with 1, according to Mathematica convention. + This is unlike in forallindexed where in accordance with Postscript + array indices start with 0. The result of MapIndexed is a list with the same number of values as the argument list. If f does not return a value, MapIndexed fails. @@ -1035,8 +1066,8 @@ BeginDocumentation Examples: - [1 2 3 4 5] {add} MapIndexed -> [1 3 5 7 9] - (abcd) {add} MapIndexed -> (aceg) + [1 2 3 4 5] {add} MapIndexed -> [2 4 6 8 10] + (abcd) {add} MapIndexed -> (bdfh) Diagnostics: None @@ -1056,6 +1087,7 @@ BeginDocumentation { mark 3 1 roll + {1 add} exch join % Mathematica indices start at 1 forallindexed_a counttomark arraystore @@ -1067,6 +1099,7 @@ BeginDocumentation { mark 3 1 roll + {1 add} exch join % Mathematica indices start at 1 forallindexed_s counttomark () exch_ @@ -1557,7 +1590,7 @@ Examples: [3 5 6 9 11] -2 MathematicaToSliIndex -> [3 5 6 9 11] 3 [3 5 6 9 11] [ -2 2 ] MathematicaToSliIndex -> [3 5 6 9 11] [3 1] -Author: Markus Diesmann (?) +Author: Markus Diesmann Remarks: Commented Ruediger Kupper @@ -1585,6 +1618,8 @@ bind def /MathematicaToSliIndex trie [/arraytype /integertype ] /MathematicaToSliIndex_i load addtotrie [/arraytype /arraytype ] /MathematicaToSliIndex_a load addtotrie + [/stringtype /integertype ] /MathematicaToSliIndex_i load addtotrie + [/stringtype /arraytype ] /MathematicaToSliIndex_a load addtotrie def %---------------------------------------------------------------------------------- <- end of line (C84) is maximum width for LaTeX-include1 @@ -1663,12 +1698,12 @@ SeeAlso: MathematicaToSliIndex { { 1 index exch - MathematicaToSliIndex_i get + MathematicaToSliIndex_i get % generalization: work with container and forall % % indexarray array subarray % - 2 index Rest - empty {pop} {Part} ifelse + 2 index Rest + empty {pop} {Part} ifelse } Map % @@ -1714,35 +1749,19 @@ SeeAlso: MathematicaToSliIndex Examples: - 5 /mul 3 /eq 15 - - [ [3 5 6 9] [11 4 7 2] [-9 1 8 10] ] [ [1 3] [2 3] ] Part - [[5 6] [1 8]] eq - - [ [3 [-12 -19] 6 9] [11 4 7 2] [-9 1 8 10] ] [ 1 2 2] Part - -19 eq - - [3 4 5 6 7] [-2] Part - 6 eq - - [3 [-9 -12] 5 6 7] [2] Part --> [-9 -12] - - [3 [-9 -12] 5 6 7] [2 2] Part --> -12 - [3 [-9 -12] 5 6 7] [[2 3]] Part [[-9 -12] 5] eq - - [3 [-9 -12] 5 6 7] [[2 3 2]] Part [[-9 -12] 5 [-9 -12]] eq - - [ [3 5 6 9] [11 4 7 2] [-9 1 8 10] ] [ 1 [] ] Part [] eq - - [ [3 5 6 9] [11 4 7 2] [-9 1 8 10] ] [ [] 1 ] Part [] eq - - [3 [5 -12] 6 9] [ [ 2 ] ] Part [[5 -12]] eq - - [3 [5 -12] 6 9] [ [ 2 ] 2] Part [-12] eq - - [ [3 5 6 9] [11 4 7 2] [-9 1 8 10] ] [ /All [3 2] ] Part - [[6 5] [7 4] [8 1]] eq + [ [3 5 6 9] [11 4 7 2] [-9 1 8 10] ] [ [1 3] [2 3] ] Part --> [[5 6] [1 8]] + [ [3 [-12 -19] 6 9] [11 4 7 2] [-9 1 8 10] ] [ 1 2 2] Part --> -19 + [3 4 5 6 7] [-2] Part --> 6 + [3 [-9 -12] 5 6 7] [2] Part --> [-9 -12] + [3 [-9 -12] 5 6 7] [2 2] Part --> -12 + [3 [-9 -12] 5 6 7] [[2 3]] Part --> [[-9 -12] 5] + [3 [-9 -12] 5 6 7] [[2 3 2]] Part --> [[-9 -12] 5 [-9 -12]] + [ [3 5 6 9] [11 4 7 2] [-9 1 8 10] ] [ 1 [] ] Part --> [] + [ [3 5 6 9] [11 4 7 2] [-9 1 8 10] ] [ [] 1 ] Part --> [] + [3 [5 -12] 6 9] [ [ 2 ] ] Part --> [[5 -12]] + [3 [5 -12] 6 9] [ [ 2 ] 2] Part --> [-12] + [ [3 5 6 9] [11 4 7 2] [-9 1 8 10] ] [ /All [3 2] ] Part --> [[6 5] [7 4] [8 1]] Bugs: Author: Diesmann @@ -1760,9 +1779,8 @@ SeeAlso: MathematicaToSliIndex [1] The Mathematica Book V4.0 "Part" */ /Part trie - [/arraytype /arraytype ] - /Part_a load - addtotrie + [/arraytype /arraytype ] /Part_a load addtotrie + [/stringtype /arraytype ] /Part_a load addtotrie def @@ -1776,13 +1794,13 @@ def %% array -n Take - take last n elements of array /Take_a_i { - dup 0 gt + dup 0 geq { - 0 exch_ getinterval_a + 0 exch_ getinterval } { - dup neg - getinterval_a + dup neg rollu MathematicaToSliIndex rolld + getinterval } ifelse } bind def @@ -1818,21 +1836,30 @@ def rolld % a jm im dup % a jm im im rollu % a im jm im - sub 1 add % a im (jm - im +1) - + sub 1 add + dup 0 lt % if 2nd parameter < 0, set it to zero to force getinterval + { % to return empty array as requested by Take in this case + pop 0 + } if + getinterval + } case 1 index 3 eq { pop dup rollu Most MathematicaToSliIndex rolld Last append - Range + Range % a r + exch % r a + container % r a c + rolld % a c r { - 1 index + 2 index exch get - } Map + append + } forall exch pop } case @@ -1850,7 +1877,7 @@ def } bind def /*BeginDocumentation -Name: Take - extract element sequences from an array +Name: Take - extract element sequences from a container Synopsis: array n Take return the first n elements array -n Take return the last n elements @@ -1858,19 +1885,35 @@ Synopsis: array [n1 n2 s] Take return elements n1 through n2 in steps of s array [[seq1]...[seqn]] Take return a nested list in which elements specified by seqi are taken at level i in list. + +Operations are the same on strings. +The implementation of Take uses the command container to abstract +the container type. + +Note that Take handles indices ranging from -N to N where + N is the length of the original container and asking for index 0 + will return an empty array. + +If the specified indices do not exist in the container, Take throws a RangeCheck error. + +If n2 < n1, Take returns an empty container. + + Examples: - [4 9 -7 3 2 11] 2 Take - -> [4 9] - [4 9 -7 3 2 11] -2 Take - -> [2 11] - [1 2 3 4 5] [-2] Take - -> 4 - [1 2 3 4 5] [1 -2] Take - -> [1 2 3 4] - [1 2 3 4 5] [1 -2 2] Take - -> [1 3] - [1 2 3 4 5] [1 -1 2] Take - -> [1 3 5] + [4 9 -7 3 2 11] 2 Take --> [4 9] + [4 9 -7 3 2 11] -2 Take --> [2 11] + [1 2 3 4 5] [-2] Take --> 4 + [1 2 3 4 5] [1 -2] Take --> [1 2 3 4] + [1 2 3 4 5] [1 -2 2] Take --> [1 3] + [1 2 3 4 5] [1 -1 2] Take --> [1 3 5] +% [1 2 3 4 5] [1 6] Take --> [Error]: RangeCheck + (HAL) {1 add} Map --> (IBM) + (HAL) 2 Take --> (HA) + (HAL) -2 Take --> (AL) + (HALLO) [-2] Take --> 76 + (HALLO) [1 -2] Take --> (HALL) + (HALLO) [1 -2 2] Take --> (HL) + (HALLO) [1 -1 2] Take --> (HLO) Author: Diesmann Bugs: @@ -1884,6 +1927,8 @@ SeeAlso: Drop, Part, MathematicaToSliIndex, getinterval, get /Take trie [/arraytype /integertype] /Take_a_i load addtotrie [/arraytype /arraytype] /Take_a_a load addtotrie +[/stringtype /integertype] /Take_a_i load addtotrie +[/stringtype /arraytype] /Take_a_a load addtotrie def @@ -1899,21 +1944,14 @@ Synopsis: array {[seq1]...[seqn]} Drop return a nested list in which elements specified by seqi are removed at level i in list. Examples: - [4 9 -7 3 2 11] 2 Drop - -> [-7 3 2 11] - [4 9 -7 3 2 11] -2 Drop - -> [4 9 -7 3] - [1 2 3 4 5] [-2] Drop - -> [1 2 3 5] - [1 2 3 4 5] [1 -2] Drop - -> [5] - [1 2 3 4 5] [1 -2 2] Drop - -> [2 4 5] - [1 2 3 4 5] [1 -1 2] Drop - -> [2 4] - - [[-9 -12] [6 7]] {[2] [1]} Drop - -> [[-12]] + [4 9 -7 3 2 11] 2 Drop --> [-7 3 2 11] + [4 9 -7 3 2 11] -2 Drop --> [4 9 -7 3] + [1 2 3 4 5] [-2] Drop --> [1 2 3 5] + [1 2 3 4 5] [1 -2] Drop --> [5] + [1 2 3 4 5] [1 -2 2] Drop --> [2 4 5] + [1 2 3 4 5] [1 -1 2] Drop --> [2 4] + + [[-9 -12] [6 7]] {[2] [1]} Drop --> [[-12]] Author: Diesmann FirstVersion: 2007.11.28 @@ -2562,7 +2600,7 @@ Examples: Author: Marc-oliver Gewaltig FirstVersion: 20.6.02 -SeeAlso: ArrayShape, Range, Table, Dimensions +SeeAlso: ArrayShape, Range, Table, Dimensions, array */ /LayoutArray { @@ -3531,6 +3569,8 @@ SeeAlso: Max, Sort, Total, Variance (Function({x+2},'x)) CompileMath --> {{x 2 add} /x Function} (f=Function({x+2},'x)) CompileMath --> {/f {x 2 add} /x Function dup rolld Set} (f={#+2}) CompileMath --> {/f {<< >> begin /# Set # 2 add end} dup rolld Set} + (f={#1-#2}) CompileMath --> {/f {<< >> begin /#2 Set /#1 Set #1 #2 sub end} dup rolld Set} + ({#1-#2}) CompileMath exec --> {<< >> begin /#2 Set /#1 Set #1 #2 sub end} ([4,3,2]) CompileMath --> {[4 3 2]} (x=7+[4,3,2]*2) CompileMath --> {/x 7 [ 4 3 2 ] 2 mul add dup rolld Set} ([]) CompileMath --> {[]} @@ -3541,6 +3581,7 @@ SeeAlso: Max, Sort, Total, Variance ( [ 3, [ 2, 1], -9] // Flatten) CompileMath exec --> [3 2 1 -9] ( [ 3, [ 2, 1], -9] // Flatten // {Select(#,{#<3})} ) CompileMath exec --> [2 1 -9] (5+3 // {#+1} ) CompileMath exec --> 9 + (7 5 // {#1-#2}) CompileMath exec --> 2 Bugs: The present version fails for doubles with negative exponents @@ -3671,22 +3712,24 @@ def BeginProcedureSymbol match out length % length - << /n_args 0 >> begin - + <> begin % dictionary to store argument names of the pure function + % in the #1, ..., #n notation. In case of only a single argument + % the # is sufficient % expr - expr_sequence % length - - -%n_args == + expr_sequence % length dup out exch Take % length first exch % first length out length sub out exch Take % first last cvx - n_args 0 gt % the procedure has arguments + + args length 0 gt { - {<< >> begin /# Set} exch join {end} join + {<< >> begin} + args Sort Reverse { cvlit append (Set) cvn append } forall + + exch join {end} join } if @@ -3914,7 +3957,7 @@ def /BeginArrayToken load /out cdict AppendTo lookahead match - lookahead /EndArraySymbol load eq + /lookahead load /EndArraySymbol load eq { /EndArrayToken load /out cdict AppendTo lookahead match @@ -3922,7 +3965,7 @@ def { { - delayedexpr % expr + expr % delayedexpr % expr lookahead /comma eq { /comma match @@ -4023,9 +4066,20 @@ def { lookahead /argument eq { - (#) cvn /out cdict AppendTo /argument match - 1 /n_args Set + lookahead type /integertype eq + { + (#) lookahead cvs join dup cvn /out cdict AppendTo + /args AppendTo + lookahead match + } + { + (#) cvn /out cdict AppendTo +% /argument match + (#) /args AppendTo +% 1 /n_args Set + } + ifelse } { lookahead /openparenthesis eq @@ -4051,7 +4105,13 @@ def dictionary } { - /unsignedfactor /SyntaxError raiseerror + lookahead /BeginProcedureSymbol load eq + { + purefunction + } + { + /unsignedfactor /SyntaxError raiseerror + } ifelse } ifelse } ifelse } ifelse @@ -4798,15 +4858,11 @@ SeeAlso: MapThread, forall, Map, MapIndexed, NestList, FoldList /size [/intvectortype] {dup length_iv} def /size [/doublevectortype] {dup length_dv} def -/eq [/intvectortype /intvectortype] -{ - intvector2array exch intvector2array eq -} def +/eq [/intvectortype /intvectortype] /eq_iv load def +/eq [/doublevectortype /doublevectortype] /eq_dv load def -/eq [/doublevectortype /doublevectortype] -{ - doublevector2array exch doublevector2array eq -} def +/neq [/intvectortype /intvectortype] {eq not} def +/neq [/doublevectortype /doublevectortype] {eq not} def /forall [/doublevectortype /proceduretype] /forall_dv load def /forall [/intvectortype /proceduretype] /forall_iv load def @@ -4860,7 +4916,7 @@ range specification. Author: Marc-Oliver Gewaltig FirstVersion: Dec. 4 2012 -SeeAlso: zeros, ones, Range +SeeAlso: zeros, ones, Range, array, LayoutArray, Table */ /arange_ /arange load def /arange [/arraytype] /arange_ load def diff --git a/lib/sli/nest-init.sli b/lib/sli/nest-init.sli index 98d5cf6004..a60976d3ec 100644 --- a/lib/sli/nest-init.sli +++ b/lib/sli/nest-init.sli @@ -33,15 +33,6 @@ M_DEBUG (nest-init.sli) (Initializing SLI support for NEST Kernel.) message % see nestmodule.cpp -/nest-init /SLI ($Revision: 10474 $) provide-component -/nest-init /C++ (1.157) require-component - -statusdict begin -/kernellibrevision - ($Revision: 10474 $) % SVN/CVS revision number (unique) -def -end - % Add NEST example directory to search-path statusdict /prgdocdir get (/examples) join addpath statusdict /prgdocdir get (/examples/FacetsBenchmarks) join addpath @@ -97,8 +88,51 @@ def %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -/cvdict trie -[/connectiontype] /cvdict_C load addtotrie + +% oosupport.sli already defines conversions for dict +/cvdict [/connectiontype] + /cvdict_C load +def + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +/* BeginDocumentation + Name: cvgidcollection - Create a container of global ids. + + Synopsis: + list_of_gids cvgidcollection -> gidcollection + first_gid last_gid cvgidcollection -> gidcollection + + Parameters: + list_of_gids - an array or intvector of global ids, or a gidcollection + first_gid - an integer definig the first GID of the range + last_gid - an integer definig the last GID of the range + + Description: + This function creates a gidcollection object, which is a unified + representation for multiple global ids of neurons or devices. To + save memory in the case of contiguous ranges of GIDs, it is + possible to just use the first and last index of the range to + initialize the gidcollection. + + Author: Jochen Martin Eppler + FirstVersion: April 2014 + + SeeAlso: cv_iv, Connect +*/ + +/cvgidcollection trie + [/integertype /integertype] /cvgidcollection_i_i load addtotrie + [/arraytype] /cvgidcollection_ia load addtotrie + [/intvectortype] /cvgidcollection_iv load addtotrie + [/gidcollectiontype] {} addtotrie +def + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% typeinit.sli already defines size functions for other types +/size [/gidcollectiontype] + /size_g load def %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -204,63 +238,245 @@ def % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + /* BeginDocumentation - Name: Connect - Establish a connection between two nodes. + Name: Connect - Establish a connection between two nodes or lists of nodes. Synopsis: - sgid tgid Connect -> - - sgid tgid /synmodel Connect -> - - sgid tgid weight delay Connect -> - - sgid tgid weight delay /synmodel Connect -> - - sgid tgid params Connect -> - - sgid tgid params /synmodel Connect -> - + source target Connect + source target syn_model Connect + source target weight delay Connect + source target weight delay syn_model Connect + source target params Connect + source target params syn_model Connect + + sources targets Connect + sources targets conn_rule Connect + sources targets conn_spec Connect + sources targets conn_rule syn_model Connect + sources targets conn_spec syn_model Connect + sources targets conn_rule syn_spec Connect + sources targets conn_spec syn_spec Connect Parameters: - sgid - Global id of the source node. - tgid - Global id of the target node. - weight - The weight of the connection - delay - The transmission delay of the connection (in ms) - params - A complete parameter dictionary for the connection - /synmodel - The synapse model for the connection (see Options below) + source integer - the GID of the source + target integer - the GID of the target + weight double - the weight of the connection + delay double - the delay of the connection + params dict - dictionary with synapse parameters + + sources array/intvector/gidcollection - the GIDs of the sources + targets array/intvector/gidcollection - the GIDs of the targets + syn_model literal - the name of the synapse model, see synapsedict + syn_spec dict - dictionary with synapse model specification (see Options) + conn_rule literal - the name of the connection rule, see connruledict + conn_spec dict - dictionary with connectivity specification (see Options) Options: - /synapse_model - the default synapse model to be used for all connections. - - This is a convenience option for the creation of many connections of the - same type. Alternatively, the synapse model can be given in each call to - Connect. + /conn_spec - dictionary with connectivity specification, must at + least contain /rule + /syn_spec - dictionary with synapse specification, must at least + contain /model Description: - 1. Connect establishes a connection between two nodes. - 2. The parameters and dynamics of the connection are determined by the - synapse model. The model can be given in the call to Connect. The - default model can be set as an Option. + Connects sources to targets according to the given connectivity + specification conn_spec. Some connection rules impose requirements. + E.g. /one_to_one requires that sources and targets have the same + number of elements. Others may have additional parameters, + e.g. connection probability /p for /pairwise_binomial. - SeeAlso: ConvergentConnect, DivergentConnect, synapsedict + The variants with two global ids as arguments implicitly connect + the two neurons using the one_to_one rule. If given, weight, delay, + syn_model, and params are used for the connection. + + The variants with only literal arguments /conn_rule or /syn_model + are shorthand for the corresponding calls with a connectivity or + synapse specification dictionaries as explained in the Options + section. The literals are expanded to << /rule /conn_rule >> and + << /model /syn_model >>, respectively. + + Parameters for connectivity rules must have fixed values. + + Parameters for synapses may be fixed single values, random deviate + specifications, or arrays of the same length as sources and targets + for the /one_to_one rule. + + SeeAlso: synapsedict, connruledict, cvgidcollection, DivergentConnect, RandomDivergentConnect, ConvergentConnect, RandomConvergentConnect + + Author: Hannah Bos, Hans Ekkehard Plesser, Jochen Martin Eppler + + FirstVersion: January 2014 */ +%%% Options for Connect + /Connect << - /synapse_model /static_synapse + /conn_spec << /rule /one_to_one >> + /syn_spec << /model /static_synapse >> >> Options -/Connect_main trie -[/integertype /integertype /literaltype] - /Connect_i_i_l load addtotrie -[/integertype /integertype /doubletype /doubletype /literaltype] - /Connect_i_i_d_d_l load addtotrie -[/integertype /integertype /dictionarytype /literaltype] - /Connect_i_i_D_l load addtotrie -def -/Connect [/literaltype] { - Connect_main -} def +%%% Helper functions for Connect -/Connect [/anytype] { - /Connect /synapse_model GetOption - Connect_main +% Expects a synapse or connection specification dictionary on the +% stack and extends it by the defaults from Connect's Options for +% all keys from the given spec in the Options for Connect that are +% missing in the given dictionary. +% Usage: dict /lit, where lit is the name of the spec in the Options +/:Connect_complete_dict { + << >> begin + /optname Set + /Connect optname GetOption keys { + dup /key Set + exch dup 3 2 roll known not { + dup key /Connect optname GetOption key get put + } if + } forall + end } def + +%%% Variants of Connect + +/Connect trie + + % Connect two nodes using default synapse model + [/integertype /integertype] { + /Connect /syn_spec GetOption /model get + Connect_i_i_l + } bind addtotrie + + % Connect two nodes using given synapse model + [/integertype /integertype /literaltype] + /Connect_i_i_l load addtotrie + + % Connect two nodes using given weight and delay and default synapse model + [/integertype /integertype /doubletype /doubletype] { + /Connect /syn_spec GetOption /model get + Connect_i_i_d_d_l + } bind addtotrie + + % Connect two nodes using given weight, delay, and synapse model + [/integertype /integertype /doubletype /doubletype /literaltype] + /Connect_i_i_d_d_l load addtotrie + + % Connect two nodes using given weight and delay and default synapse model + [/integertype /integertype /dictionarytype] { + /Connect /syn_spec GetOption /model get + Connect_i_i_D_l + } bind addtotrie + + % Connect two nodes using given synapse parameters and synapse model + [/integertype /integertype /dictionarytype /literaltype] + /Connect_i_i_D_l load addtotrie + + + % We create the type trie for the list variants using a loop + [/arraytype /intvectortype /gidcollectiontype] { + /gidlisttype Set + + % Connect nodes from two lists of GIDs using default rule and + % default syn_model + [gidlisttype gidlisttype] { + cvgidcollection exch % convert targets to gidcollection + cvgidcollection exch % convert sources to gidcollection + /Connect /conn_spec GetOption % use defaults + /Connect /syn_spec GetOption % use defaults + Connect_g_g_D_D + } bind addtotrie + + % Connect nodes from two lists of GIDs using given rule and + % default synapse model + [gidlisttype gidlisttype /literaltype] { + mark exch /rule exch >> % create the conn_spec dictionary + /conn_spec :Connect_complete_dict % fill in missing defaults + 3 1 roll % bring sources and targets to top + cvgidcollection exch % convert targets to gidcollection + cvgidcollection exch % convert sources to gidcollection + 3 2 roll % bring sources and targets to bottom + /Connect /syn_spec GetOption % use defaults + Connect_g_g_D_D + } bind addtotrie + + % Connect nodes from two lists of GIDs using given rule + % paramters and default synapse model + [gidlisttype gidlisttype /dictionarytype] { + /conn_spec :Connect_complete_dict % fill in missing defaults + 3 1 roll % bring sources and targets to top + cvgidcollection exch % convert targets to gidcollection + cvgidcollection exch % convert sources to gidcollection + 3 2 roll % bring sources and targets to bottom + /Connect /syn_spec GetOption % use defaults + Connect_g_g_D_D + } bind addtotrie + + % Connect nodes from two lists of GIDs using given rule and + % given synapse model + [gidlisttype gidlisttype /literaltype /literaltype] { + mark exch /model exch >> % create the syn_spec dictionary + /syn_spec :Connect_complete_dict % fill in missing defaults + exch % exchange syn_spec and conn_spec + mark exch /rule exch >> % create the conn_spec dictionary + /conn_spec :Connect_complete_dict % fill in missing defaults + exch % exchange syn_spec and conn_spec + 4 2 roll % bring sources and targets to top + cvgidcollection exch % convert targets to gidcollection + cvgidcollection exch % convert sources to gidcollection + 4 2 roll % bring sources and targets to bottom + Connect_g_g_D_D + } bind addtotrie + + % Connect nodes from two lists of GIDs using given rule and + % given syn_spec + [gidlisttype gidlisttype /literaltype /dictionarytype] { + /syn_spec :Connect_complete_dict % fill in missing defaults + exch % exchange syn_spec and conn_spec + mark exch /rule exch >> % create the conn_spec dictionary + /conn_spec :Connect_complete_dict % fill in missing defaults + exch % exchange syn_spec and conn_spec + 4 2 roll % bring sources and targets to top + cvgidcollection exch % convert targets to gidcollection + cvgidcollection exch % convert sources to gidcollection + 4 2 roll % bring sources and targets to bottom + Connect_g_g_D_D + } bind addtotrie + + % Connect two lists using the given rule parameters and synapse model + [gidlisttype gidlisttype /dictionarytype /literaltype] { + mark exch /model exch >> % create the syn_spec dictionary + /syn_spec :Connect_complete_dict % fill in missing defaults + exch % exchange syn_spec and conn_spec + /conn_spec :Connect_complete_dict % fill in missing defaults + exch % exchange syn_spec and conn_spec + 4 2 roll % bring sources and targets to top + cvgidcollection exch % convert targets to gidcollection + cvgidcollection exch % convert sources to gidcollection + 4 2 roll % bring sources and targets to bottom + Connect_g_g_D_D + } bind addtotrie + + % Connect two lists using the given rule parameters and synapse + % parameters + [gidlisttype gidlisttype /dictionarytype /dictionarytype] { + /syn_spec :Connect_complete_dict % fill in missing defaults + exch % exchange syn_spec and conn_spec + /conn_spec :Connect_complete_dict % fill in missing defaults + exch % exchange syn_spec and conn_spec + 4 2 roll % bring sources and targets to top + cvgidcollection exch % convert targets to gidcollection + cvgidcollection exch % convert sources to gidcollection + 4 2 roll % bring sources and targets to bottom + Connect_g_g_D_D + } bind addtotrie + + } forall + +def + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + /* BeginDocumentation Name: GetConnections - Retrieve connections between nodes @@ -314,9 +530,15 @@ def /GetConnections /ArgumentError raiseerror } if + pdict key get + TensorRank 1 eq not + { + key cvs ( list of GIDs must be of dimension 1) join M_ERROR message + /GetConnections /ArgumentError raiseerror + } + if } if } forall - pstack GetConnections_D Flatten } def @@ -448,7 +670,7 @@ def } def /DivergentConnect [/anytype] { - /Connect /synapse_model GetOption + /Connect /syn_spec GetOption /model get DivergentConnect_main } def @@ -570,8 +792,8 @@ Options: allow_autapses - controls, whether self connections can be produced. allow_multapses - controls, whether multiple selections are possible. -If not given, the synapse model is taken from the Options dictionary -of the Connect command. +If not given, the synapse model is taken from the syn_spec dictionary +from the Options of the Connect command. Description: @@ -650,7 +872,7 @@ def } def /RandomDivergentConnect [/anytype] { - /Connect /synapse_model GetOption + /Connect /syn_spec GetOption /model get RandomDivergentConnect_main } def @@ -675,7 +897,7 @@ def } def /ConvergentConnect [/anytype] { - /Connect /synapse_model GetOption + /Connect /syn_spec GetOption /model get ConvergentConnect_main } def @@ -692,23 +914,25 @@ Synopsis: [sources] [targets] n /synmodel RandomConvergentConnect -> - Parameters: -[sources] - array of (global IDs of) potential source nodes -target - GID of target node -[targets] - array of (global IDs of) target nodes -n - number of connections to be established -init_dict - dictionary used to initialize each of the established connections -weights - A list of weights of size n -delays - A list of delays of size n -weightss - A list of lists of weights of size length(targets) x size n -delayss - A list of lists delays of size length(targets) x size n -/synmodel - The synapse model for the connection (see Options below) +[sources] - array of (global IDs of) potential source nodes +target - GID of target node +[targets] - array of (global IDs of) target nodes +source_from - first index in range +source_to - last index in range +n - number of connections to be established +init_dict - dictionary used to initialize each of the established connections +weights - A list of weights of size n +delays - A list of delays of size n +weightss - A list of lists of weights of size length(targets) x size n +delayss - A list of lists delays of size length(targets) x size n +/synmodel - The synapse model for the connection (see Options below) Options: allow_autapses - controls, whether self connections can be produced. allow_multapses - controls, whether multiple selections are possible. -If not given, the synapse model is taken from the Options dictionary -of the Connect command. +If not given, the synapse model is taken from the syn_spec dictionary +from the Options of the Connect command. Description: This function connects a given target node with a random collection of @@ -882,7 +1106,8 @@ bind def 4 -1 roll LayoutArray 3 2 roll - + + % put empty arrays for weights before synapse type [ ] % weights empty [ ] % delays empty 3 2 roll @@ -894,6 +1119,7 @@ bind def RandomConvergentConnect_ia_ia_ia_daa_daa_b_b_l } bind def + % all calls without init_dict are forwarded to C++ /RandomConvergentConnect_main trie [/arraytype /integertype /integertype /literaltype] @@ -915,98 +1141,13 @@ def /RandomConvergentConnect trie [/literaltype] /RandomConvergentConnect_main load addtotrie [/anytype] { - /Connect /synapse_model GetOption + /Connect /syn_spec GetOption /model get RandomConvergentConnect_main } bind addtotrie def %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -/* BeginDocumentation -Name: BinomialConvergentConnect - Connect a target to a binomial number of sources. -Synopsis: -[sources] target c BinomialConvergentConnect -> - - -Parameters: -[sources] - array of (global IDs of) potential source nodes -target - GID of target node -c - probability of a potential connection to be established - -Options: -allow_autapses - controls, whether self connections can be produced. -allow_multapses - controls, whether multiple selections are possible. - -Description: -The function connects a given target node with each of the nodes -specified in the source array with probability c. The resulting -number of inputs to the target neuron is a binomially distributed -random number. Hence, the name. The parameters of the distribution -are the length of the source array and the connection probability c. -One way to implement BinomialConnect is to draw a binomially distributed -random number followed by a call of RandomConvergentConnect. - -Author: Diesmann -SeeAlso: RandomConvergentConnect -*/ - -% default options -/BinomialConvergentConnect << - /allow_multapses true - /allow_autapses true ->> Options - - -/BinomialConvergentConnect_ia_i_d_l -{ - % note: protection against impossible multapse/autapse - % requirements handled by RandomConvergentConnect_ia_i_b_b_l - - /BinomialConvergentConnect GetOptions begin - << >> begin %% open local namespace for variables - /synmodel Set - /c Set - /target Set - dup - /source_neurons Set - length /n Set - - target GetStatus /local get - { - target GetVpRNG /rng Set - - rng rdevdict /binomial get CreateRDV /bino Set - bino << /p c /n n >> SetStatus - - - source_neurons - target - bino Random - allow_multapses - allow_autapses - synmodel - RandomConvergentConnect_ia_i_i_b_b_l - - } if % of if target is local - end -} def - - -/BinomialConvergentConnect_main trie -[/arraytype /integertype /doubletype /literaltype] - /BinomialConvergentConnect_ia_i_d_l load addtotrie -def - -/BinomialConvergentConnect [/literaltype] { - RandomConvergentConnect_main -} def - -/BinomialConvergentConnect [/anytype] { - /Connect /synapse_model GetOption - RandomConvergentConnect_main -} def - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - /*BeginDocumentation Name: FindConnections - Find connections that fulfill the given criteria @@ -1026,7 +1167,7 @@ def parameters of the connections. If no connections were found, the returned array is empty. - This function is deprecated and will disappear in future version. + This function is deprecated and will disappear in a future version. Please use GetConnections instead. Remarks: @@ -1038,10 +1179,6 @@ def SeeAlso: GetConnections, GetStatus, SetStatus */ -%/FindConnections trie -% [/dictionarytype ] /FindConnections_D load addtotrie -%def - /FindConnections [/dictionarytype] { @@ -1055,6 +1192,7 @@ def end GetConnections Flatten } def + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /* BeginDocumentation @@ -1634,6 +1772,10 @@ def /TimeCommunication trie [/integertype /integertype /booltype] /TimeCommunication_i_i_b load addtotrie [/integertype /integertype] { false TimeCommunication_i_i_b } bind addtotrie +def + +/TimeCommunicationv trie +[/integertype /integertype] /TimeCommunicationv_i_i load addtotrie def /* BeginDocumentation @@ -1741,4 +1883,4 @@ Description: { statusdict /exitcodes get /userabort get statusdict /is_mpi get { MPI_Abort }{ quit_i } ifelse -} bind def \ No newline at end of file +} bind def diff --git a/lib/sli/oosupport.sli b/lib/sli/oosupport.sli index 60165113e8..99238ce2ab 100644 --- a/lib/sli/oosupport.sli +++ b/lib/sli/oosupport.sli @@ -20,10 +20,6 @@ * */ -/oosupport /SLI ($Revision: 9952 $) provide-component -/oosupport /C++ (1.4) require-component - -% /*BeginDocumentation Name: call - Execute object from a dictionary. Synopsis: dict /f call -> - @@ -95,11 +91,19 @@ SeeAlso: cvdict, call, SetStatus, GetStatus /*BeginDocumentation Name:cvdict - Convert argument to a dictionary -Synopsis:dict cvdict -> dict -Parameters: a dictionary which may be labeled for oo-programming -Description: In case the argument is labeled as a dictionary used as +Synopsis: dict cvdict -> dict + array cvdict -> dict +Parameters: +- a dictionary which may be labeled for oo-programming +- a flat array of even length containing key value pairs +Description: +In case the argument is labeled as a dictionary used as an object in oo-programming, this label is removed. cvdict does not clone its argument. This is the inverse function of cvo. +In case the argument is an array the resulting new dictionary contains +the key value pairs . +Examples: + [/a 1 /b 2] cvdict --> << /a 1 /b 2 >> Author:Diesmann FirstVersion: 2008-08-23 SeeAlso: cvo, clonedict @@ -110,6 +114,12 @@ SeeAlso: cvo, clonedict } def +/cvdict [/arraytype] +{ + << >> dup begin exch arrayload 2 div {def} repeat +} +def + /*BeginDocumentation Name:SetStatus_dict - Modify a dictionary used as an object in oo-programming diff --git a/lib/sli/processes.sli b/lib/sli/processes.sli index a90bdf9476..851c62d1e6 100644 --- a/lib/sli/processes.sli +++ b/lib/sli/processes.sli @@ -20,18 +20,6 @@ * */ -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% -%% This is the SLI-library defining wrapper-routines -%% for the functions defined in module "processes.{h|cc}". -%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -/processes /SLI ($Revision: 10020 $) provide-component -/processes /C++ (1.48) require-component - - - /* BeginDocumentation Name: is_mpi - flag in statusdict indicating whether interpreter was compiled with MPI diff --git a/lib/sli/ps-lib.sli b/lib/sli/ps-lib.sli index acb5824d27..445c78de02 100644 --- a/lib/sli/ps-lib.sli +++ b/lib/sli/ps-lib.sli @@ -21,17 +21,13 @@ */ -/ps-lib ($Revision: 10098 $) provide - - - %% Library for PS conforming operators which are not %% strictly needed by the startup process. /* BeginDocumentation Name: array - construct array with n zeros (PS) Synopsis: int array -> array Examples: 10 array ->[0 0 0 0 0 0 0 0 0 0] -Author: docu by Sirko Straube +SeeAlso: Range, LayoutArray, Table, arraystore */ /array trie @@ -89,26 +85,41 @@ def /* BeginDocumentation Name: round - Round double to the nearest integer +Synopsis: double round -> double + integer round -> double Description: Alternatives: Function round_d (undocumented) -> behaviour and synopsis are the same. +Examples: +1.4 round --> 1.0 +1.5 round --> 2.0 +2 round --> 2.0 + Remarks: round_d is currently defined in SLI, could be implemented in C++ for efficiency. +On 130610 it was decided that round applied to an integer +should be the identity function. + +Update: In a later discussion, it was decided to make round +return a double in this case as well. + + Author: introduced non-trie-variant round_d, Ruediger Kupper. -SeeAlso: iround, floor, ceil +SeeAlso: iround, floor, ceil, cvi */ /round trie [/doubletype] /round_d load addtotrie + [/integertype] {cvd} addtotrie def /* BeginDocumentation Name: iround - Round and convert double to the nearest integer -Synopsis: double round -> int +Synopsis: double iround -> int Description: Round the argument to the nearest integer and converts it to type int. Examples: diff --git a/lib/sli/regexp.sli b/lib/sli/regexp.sli index 0c0c2f1394..082325eac1 100644 --- a/lib/sli/regexp.sli +++ b/lib/sli/regexp.sli @@ -20,10 +20,6 @@ * */ -/regexp /SLI ($Revision: 9988 $) provide-component -/regexp /C++ (1.3) require-component - - /* BeginDocumentation Name: regcomp - Create a regular expression Synopsis: string integer regcomp -> regex diff --git a/lib/sli/sli-init.sli b/lib/sli/sli-init.sli index 144f87155d..ece9ef0f3f 100644 --- a/lib/sli/sli-init.sli +++ b/lib/sli/sli-init.sli @@ -235,12 +235,20 @@ def %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Initialize Error Dictionary %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -errordict /recordstacks true put_d %% Enable stack snapshot on error -errordict /newerror false put_d %% Initialize -errordict /commandname () put_d -errordict /oldcommandname () put_d -errordict /olderrorname () put_d -errordict /oldestack () put_d +/init_errordict +{ + errordict /recordstacks true put_d %% Enable stack snapshot on error + errordict /newerror false put_d %% Initialize + errordict /commandname () put_d + errordict /oldcommandname () put_d + errordict /olderrorname () put_d + errordict /oldestack () put_d + errordict /estack [ ] put_d + errordict /dstack [ ] put_d + errordict /ostack [ ] put_d +} def + +init_errordict /raiseerror trie [/literaltype /literaltype] /raiseerror load addtotrie @@ -698,12 +706,20 @@ def /:clicclocs clic cloc def /* BeginDocumentation - Name: reset - Reset dictionary stack and clear the userdict + Name: reset - Reset the SLI interpreter + Description: + reset re-initializes most of the SLI interpreter by clearing the operand stack, the dictionary stack, + and the userdict. reset also clears the error state. + Non-standard symbols and data defined in any of the other dictionaries, such as the statusdict or systemdict remain unchanged. + SeeAlso: ResetKernel */ /reset { + errordict /new_error false put_d + init_errordict + clear % operand stack cleardictstack userdict cleardict } bind def @@ -1537,8 +1553,66 @@ SeeAlso: GNUreadline quit_i } bind def +/* +BeginDocumentation +Name: save - save interpreter state in a state dictionary +Synopsis: save -> statedict true +Description: + +Experimental function to save the interpreter state into a state dictionary. +The state can then be restored, using the command restore. +After restore, execution will resume with the next command after 'save'. +The boolean return value can be used to branch execution after saving or restoring the state. + +Examples: + +save and restore can be used to implement non-local jumps within procedures and even between procedures. +A saved state defines a jump position to which the execution can return by calling restore for this state. + +SeeAlso: resore +Author: Marc-Oliver Gewaltig +*/ +/save +{ + (save) = + << >> begin + operandstack /ostack Set + execstack [1 -4] Take /estack Set + errordict /errdict Set + currentdict end + dup /dstack dictstack put_d + true +} def + +/* +BeginDocumentation +Name: restore - restore interpreter state from state dictionary +synopsis: statedict restore -> false +Description: + +Experimental function to restore the interpreter state from a previously stored state +dictionary, created by the command save. +After restore, execution will resume with the next command after 'save'. +The boolean return value can be used to branch execution after saving or restoring the state. + +Bugs: Currently, the state of the dictionary stack cannot be restored. + +SeeAlso: save +Author: Marc-Oliver Gewaltig +*/ + +/restore +{ + begin + currentdict /ostack get restoreostack false + currentdict /errdict get systemdict /errordict rolld put + currentdict end + %dup /dstack get restoredstack + /estack get restoreestack +} def + /* BeginDocumentation Name: exithook - Procedure executed if the executive mode is left. @@ -1748,17 +1822,6 @@ SeeAlso: nestrc cout (Built on ) <- built <- ( for ) <- host <- endl (Architecture: ) <- statusdict /architecture get /long get 8 mul <- ( bit) <- endl - (SLI revison: ) <- stdlibrevision <- endl - - /kernelname lookup - { % we are running the interpreter with a simulation kernel - <- ( revision: ) <- kernelrevision <- endl - (Kernel library rev: ) <- kernellibrevision <- endl - } - { % we are running the pure interpreter - (no simulation kernel linked.) <- endl - } - ifelse (Searching files in: ) <- path <-- endl pop end @@ -1824,26 +1887,6 @@ SeeAlso: page /searchfile /:searchfile_debug load def -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Define unique Library Version -%% (note: depends on misc_helpers.sli for "breakup") -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -/* BeginDocumentation -Name: stdlibrevision - revision number of sli-init libray -Description: String constants which contains the unique CVS revision -number of the SLI startup file. This value can be -used by custom programs to check whether certain features -ought to be present. - -This symbol is defined in the status dictionary. -*/ - -statusdict begin -/stdlibrevision - ($Revision: 10138 $) % CVS revision number (unique) -def -end - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % ENVVAR :pathlist -> array % % UNDOCUMENTED % @@ -1865,25 +1908,20 @@ end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % SLI library handling % -% (see library.sli) % -% and support: % -% Version number handling routines % -% (see library.sli) % % % % This should be initialized as early as % % possible, so that other initialization % -% diles can use the library management! % +% files can use the library management! % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% (library.sli) run -(version.sli) run % note: version.sli depends on misc_helpers.sli %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% PS conforming operators % +%% PS conforming operators %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -/ps-lib (1.2) require +(ps-lib) run %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1978,7 +2016,9 @@ moduleinitializers */ /:commandline { + systemdict begin /scripterror statusdict /exitcodes get /scripterror get def + end statusdict /argv get Rest << >> begin @@ -2012,13 +2052,16 @@ moduleinitializers pop exit } if - dup 0 11 getinterval (--userargs=) eq + size 11 geq { - size 11 sub % stack: (--userargs=...) size-11 - 11 exch getinterval % stack: (...) - (:) breakup - statusdict /userargs rolld put - exit + dup 0 11 getinterval (--userargs=) eq + { + size 11 sub % stack: (--userargs=...) size-11 + 11 exch getinterval % stack: (...) + (:) breakup + statusdict /userargs rolld put + exit + } if } if dup (-c) eq @@ -2125,9 +2168,6 @@ moduleinitializers */ /start { - - /scripterror statusdict /exitcodes get /scripterror get def - { :commandline { % we have an interactive session @@ -2277,6 +2317,20 @@ SeeAlso: welcome } def +/* BeginDocumentation +Name: environment - return dictionary of environment variables +Synopsis: enviroment -> dict +Description: +Returns dictionary with the environment variables of the process that +invoked NEST. It is a shortcut for statusdict/environment ::, provided +for backward compatibility. +SeeAlso: statusdict +*/ +/environment +{ + statusdict/environment :: +} def + end % systemdict (SLIUSER) :pathlist path setpath % prepend user directories @@ -2286,15 +2340,30 @@ evalrcfile /* BeginDocumentation -Name: environment - return divtionary of environment variables -Synopsis: enviroment -> dict -Description: -Returns dictionary with the environment variables of the process that -invoked NEST. It is a shortcut for statusdict/environment ::, provided -for backward compatibility. +Name: is_threaded - returns true if NEST/SLI was compiled with thread support +Synopsis: is_threaded -> bool +Description: +Returns true if NEST/SLI was compiled with support for threads, and returns +false otherwise. SeeAlso: statusdict */ -/environment +/is_threaded { - statusdict/environment :: + % We must test against "no", if threads are supported threading is a + % string containing the threading model. + statusdict/threading :: (no) neq } def + +/* BeginDocumentation +Name: is_threaded_with_openmp - returns true if NEST/SLI was compiled with OpenMP support +Synopsis: is_threaded_with_openmp -> bool +Description: +Returns true if NEST/SLI was compiled with support for OpenMP threads, and returns +false otherwise. +SeeAlso: statusdict +*/ +/is_threaded_with_openmp +{ + statusdict/threading :: ToLowercase (openmp) searchif +} def + diff --git a/lib/sli/typeinit.sli b/lib/sli/typeinit.sli index 2f912f053e..63ec631fe4 100644 --- a/lib/sli/typeinit.sli +++ b/lib/sli/typeinit.sli @@ -354,11 +354,21 @@ def [/anytype /anytype] /eq_ load addtotrie def +/neq_ /neq load def +/neq trie + [/anytype /anytype] /neq_ load addtotrie +def + /not trie [/booltype ] /not_b load addtotrie [/integertype] /not_i load addtotrie def +/xor_ /xor load def +/xor trie + [/booltype /booltype] /xor_ load addtotrie +def + /and_bb /and load def /and trie [/booltype /booltype ] /and_bb load addtotrie @@ -532,10 +542,38 @@ def [/arraytype ] /shrink_a load addtotrie def + +/*BeginDocumentation +Name: references - Returns the number of references to a reference counted object. +Synopsis: array references -> array integer + dict references -> dict integer +Description: references returns the number of references to +a reference counted object including potential self references. +Examples: << /x 0 >> dup references -> dict dict 2 + [ 0 ] dup references -> array array 2 +SeeAlso: selfreferences, testsuite::test_dict_basic_self_reference +*/ /references trie [/arraytype ] /references_a load addtotrie + [/dictionarytype ] /references_d load addtotrie def + +/*BeginDocumentation +Name: selfreferences - Returns the number of selfreferences of a reference counted object. +Synopsis: dict selfreferences -> dict integer +Description: selfreferences returns the number of references to +a reference counted object. In the present implementation only first level +self references are handled. +Examples: << /x 0 >> dup dup begin /x Set end selfreferences -> dict 1 +SeeAlso: references, testsuite::test_dict_basic_self_reference +*/ +/selfreferences trie + [/dictionarytype ] /selfreferences_d load addtotrie +def + + + /*BeginDocumentation Name: cvx - convert array/string to procedure @@ -578,10 +616,11 @@ BeginDocumentation Examples: - 3.33 cvi -> 3 - (23) cvi -> 23 - (23.2323) cvi -> 23 - (hello) cvi -> 0 + 3.33 cvi --> 3 + 2 cvi --> 2 + (23) cvi --> 23 + (23.2323) cvi --> 23 + (hello) cvi --> 0 Diagnostics: no errors are issued. @@ -649,6 +688,42 @@ def [/trietype /arraytype /anytype] /addtotrie load addtotrie def + +/* BeginDocumentation +Name: eval - evaluate a string of SLI code +Synopsis: string eval -> obj1 ... objn + +Description: +Reads a string and evaluates its content. The resulting objects are +pushed onto the stack. + +As in regular batch mode the interpreter reads tokens from a +stream, a string stream in this case, and immediately executes the +incoming language constructs. + +An alternative implementation is cvx exec. Here cvx calls cst to +first create an array of token from the string which is then converted +to a procedure. + +The function evalstring uses cvx and executs the procedure in a +separate stopped context using the standard error handler. + +A similar function to eval also occurs in Python. + +Examples: + (1 2 add) eval --> 3 + ([1 2 3] /peter 5 def) eval --> [1 2 3] + +Author: Jochen M. Eppler +FirstVersion: June 2013 +SeeAlso: cvx, exec, cst, evalstring, token +*/ + +/eval [/stringtype] { + isstream pop cvx exec +} def + + /* BeginDocumentation Name: token - read a token from a stream or string Synopsis: string token -> post any true @@ -828,40 +903,34 @@ def [/booltype] /not_b load addtotrie def -/* -BeginDocumentation - - Name: cva - Convert dictionary/trie to array +/* BeginDocumentation - Synopsis: dict cva -> array - trie cva -> array + Name: cva - Converts argument to an array - Description: cva converts a given dictionary/trie to an array. - The contents of the dictionay is mapped to the array in a - form which is similar to the construction of an array, namely - << key1 val1 ... keyn valn>> cva -> [key1 val1 ... keyn valn] + Synopsis: dict cva -> array + trie cva -> array + array cva -> array + intvector cva -> array + doublevector cva -> array + iterator cva -> array - Parameters: - dict is a dictionary which may be empty - trie is a type trie + Description: cva converts the argument to an array. The + array is shaped close to a form usable to recreate the original + data type. In case the argument is already an array, cva is + applied recursively. Examples: - << /a 1 /b 2>> cva -> [/a 1 /b 2] - /add load cva == shows trie for add. - - Diagnostics: - no errors are issued. - Remarks: - The name follows the convention of PostScript and stands for - ConVert to Array. - This is a typesafe wrapper to cva_d/cva_t. + << /a 1 /b 2>> cva --> [/a 1 /b 2] + /square trie [/doubletype] { dup mul } addtotrie exch pop cva --> [/doubletype [{dup mul}]] + [ << /a 1 >> << /b 2>>] cva --> [[/a 1] [/b 2]] + [1 3 -5 2] cv_iv cva --> [1 3 -5 2] + [1. 3. -5. 2.] cv_dv cva --> [1. 3. -5. 2.] + [2 10] RangeIterator cva --> [2 3 4 5 6 7 8 9 10] - Author: - Marc-oliver Gewaltig + Author: Marc-oliver Gewaltig SeeAlso: <<>>, trie, cst, cv1d, cv2d, cva_d, cva_t, cvd, cvi, cvlit, cvn, cvs, cvt_a - */ /trieheads_iter diff --git a/lib/sli/unittest.sli b/lib/sli/unittest.sli index 06910f787c..546bbd52ed 100644 --- a/lib/sli/unittest.sli +++ b/lib/sli/unittest.sli @@ -33,9 +33,23 @@ %% hans.ekkehard.plesser@umb.no %% -/unittest ($Revision: 9990 $) provide /unittest namespace +/* BeginDocumentation +Name: unittest::exit_test_gracefully - End test script and report success +Synopsis: exit_test_gracefully -> - +Description: +This function will terminate NEST/SLI with a return code signaling success. +It should be used to leave test scripts that have special prerequisites. +Example: +/unittest using +is_threaded_with_openmp not { exit_test_gracefully } if +*/ +/exit_test_gracefully +{ + statusdict/exitcodes/success :: quit_i +} def + /* BeginDocumentation Name: unittest::assert_or_die - Check condition and quit with exit code 1 if it fails @@ -228,9 +242,7 @@ SeeAlso: unittest::assert_or_die, unittest::pass_or_die, assert, quit { << exch /func exch >> begin - - mark % to remove debris from stack after error - + /func load stopped not % got a problem if we were NOT stopped { M_FATAL (unittest::fail_or_die) @@ -249,8 +261,8 @@ SeeAlso: unittest::assert_or_die, unittest::pass_or_die, assert, quit errordict /command undef errordict begin /newerror false def end - % clear stack - counttomark npop pop % need to mark separately + % restore stack + errordict /ostack get restoreostack end } bind def @@ -579,7 +591,7 @@ SeeAlso: unittest::ToUnitTestPrecision 1 MapAt % reduce to first entry available at this resolution d [1 1] Part sub 1 add % index in data array m append /r Set % distance between available data points - + d r Take [/All [2 -1]] Part /di AppendTo @@ -1330,4 +1342,4 @@ SeeAlso: unittest::distributed_assert_or_die, nest_indirect, unittest::mpirun_s } def -end +end % /unittest namespace diff --git a/lib/sli/version.sli b/lib/sli/version.sli deleted file mode 100644 index 7ce273bb87..0000000000 --- a/lib/sli/version.sli +++ /dev/null @@ -1,496 +0,0 @@ -/* - * version.sli - * - * This file is part of NEST. - * - * Copyright (C) 2004 The NEST Initiative - * - * NEST 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 2 of the License, or - * (at your option) any later version. - * - * NEST 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 NEST. If not, see . - * - */ - -/* - SLI version number handling library - - Note: this file depends on misc_helpers.sli, - because it uses "breakup", "reverse", and - "SLIFunctionWrapper". - Hence misc_helpers.sli must be loaded first - in sli-init.sli. -*/ - - -%% note: this library cannot use the provide/require mechanism, because this -%% would lead to infinite recuresion during initialization! - - -/version namespace - - %%%%%% - % pad version arrays with zeros to make them same length - %%%%%% - /:padversions[/arraytype /v1 /arraytype /v2] - { - v1 length v2 length max /m Set - v1 m v1 length sub array join - v2 m v2 length sub array join - } bind SLIFunctionWrapper - - -/* BeginDocumentation -Name: version::validate - Assure correct format of version number array. - -Synopsis: [version] validate -> - - -Description: -Assures that the passed array is composed of truly positive integers -only, and contains at least one element. - -Parameters: -[version] - Version number array. See [1] for details. - -Examples: -[1 23 5] validate -> - -[] validate -> (raises /SytaxError) -[1 -23 5] validate -> (raises /SytaxError) -[1 2.3 5] validate -> (raises /SytaxError) - -Diagnostics: -If argument is no valid version number array, an error message is -issued and /SytaxError is raised. - -Author: Ruediger Kupper - -FirstVersion: 29-jul-2003 - -Availability: SLI2.0, library: version - -References: -[1] Ruediger Kupper, SLI library management, - HRI-EU Report 06/05, Honda Research Institute Europe GmbH, 2006. - -SeeAlso: version::validate, version::vcmp, version::veq, version::vlt, version::vgt, version::vleq, version::vgeq, version::s2v, version::v2s -*/ - /validate[/arraytype /v] - { - v length 0 eq - { - M_ERROR funcname cvs (Version number array must contain at least one number.) message - funcname /SyntaxError raiseerror - } if - v - { - dup - type /integertype neq - { - pop - M_ERROR funcname cvs (Version number array must contain integers only.) message - funcname /SyntaxError raiseerror - } if - 0 lt - { - M_ERROR funcname cvs (Version number array must contain positive integers only.) message - funcname /SyntaxError raiseerror - } if - } forall - } bind SLIFunctionWrapper - - -/* BeginDocumentation -Name: version::vcmp - Compare two version number arrays. - -Synopsis: [version1] [version2] vcmp -> -1 | 0 | +1 - -Description: -Compare two version number arrays. The result is - 0, if version1 equals version2 - -1, if version1 is smaller than version2 - +1, if version1 is greater than version2 - -The common semantics of version numbers is applied, e.g.: - [1 5] = [1 5 0 0 0 0 0] - [1 5] > [1 4] - [1 5] > [1] - [1 5] > [1 4 99 99 99] - [1 5] < [2 0] - [1 5] < [1 5 1] - [1 1] < [1 10] -etc. - -Parameters: -version{1|2} - Version number arrays (see version::validate and [1]). - -Examples: -[1 5] [1 5 0 0 0 0 0] vcmp -> 0 -[1 5] [1 4] vcmp -> 1 -[1 5] [1 5 1] vcmp -> -1 - -Diagnostics: -/SyntaxError is raised, if parameters are no valid version number -arrays (see version::validate). - -Author: Ruediger Kupper - -FirstVersion: 29-jul-2003 - -Availability: SLI2.0, library: version - -References: -[1] Ruediger Kupper, SLI library management, - HRI-EU Report 06/05, Honda Research Institute Europe GmbH, 2006. - -SeeAlso: version::validate, version::vcmp, version::veq, version::vlt, version::vgt, version::vleq, version::vgeq, version::s2v, version::v2s -*/ - /vcmp[/arraytype /v1 /arraytype /v2] - { - v1 validate v2 validate - v1 v2 :padversions /v2 Set /v1 Set - /result 0 def - 0 1 v1 length 1 sub { - /i Set - v2 i get /n2 Set - v1 i get /n1 Set - n1 n2 lt {/result -1 def exit} if - n1 n2 gt {/result +1 def exit} if - % it's neither greater nor smaller, so contine. - } for - result - } bind SLIFunctionWrapper - - -/* BeginDocumentation -Name: version::veq - Are two version number arrays equal? - -Synopsis: [version1] [version2] veq -> true | false - -Description: -Compare two version number arrays. The result is - true, if version1 equals version2 - false, otherwise - -The common semantics of version numbers is applied, see version::vcmp. - -Parameters: -version{1|2} - Version number arrays (see version::validate and [1]). - -Examples: -[1 5] [1 5 0 0 0 0 0] veq -> true -[1 5] [1 4] veq -> false - -Diagnostics: -/SyntaxError is raised, if parameters are no valid version number -arrays (see version::validate). - -Author: Ruediger Kupper - -FirstVersion: 29-jul-2003 - -Availability: SLI2.0, library: version - -References: -[1] Ruediger Kupper, SLI library management, - HRI-EU Report 06/05, Honda Research Institute Europe GmbH, 2006. - -SeeAlso: version::validate, version::vcmp, version::veq, version::vlt, version::vgt, version::vleq, version::vgeq, version::s2v, version::v2s -*/ - /veq[/arraytype /arraytype] - { - vcmp 0 eq - } bind def - - -/* BeginDocumentation -Name: version::vlt - "Less than" for version number arrays. - -Synopsis: [version1] [version2] vlt -> true | false - -Description: -Compare two version number arrays. The result is - true, if version1 is less than version2 - false, otherwise - -The common semantics of version numbers is applied, see version::vcmp. - -Parameters: -version{1|2} - Version number arrays (see version::validate and [1]). - -Examples: -[1 5] [1 5 0 0 0 0 0] vlt -> false -[1 5] [1 4] vlt -> false -[1 5] [1 5 1] vlt -> true - -Diagnostics: -/SyntaxError is raised, if parameters are no valid version number -arrays (see version::validate). - -Author: Ruediger Kupper - -FirstVersion: 29-jul-2003 - -Availability: SLI2.0, library: version - -References: -[1] Ruediger Kupper, SLI library management, - HRI-EU Report 06/05, Honda Research Institute Europe GmbH, 2006. - -SeeAlso: version::validate, version::vcmp, version::veq, version::vlt, version::vgt, version::vleq, version::vgeq, version::s2v, version::v2s -*/ - /vlt[/arraytype /arraytype] - { - vcmp -1 eq - } bind def - - -/* BeginDocumentation -Name: version::vgt - "Greater than" for version number arrays. - -Synopsis: [version1] [version2] vgt -> true | false - -Description: -Compare two version number arrays. The result is - true, if version1 is greater than version2 - false, otherwise - -The common semantics of version numbers is applied, see version::vcmp. - -Parameters: -version{1|2} - Version number arrays (see version::validate and [1]). - -Examples: -[1 5] [1 5 0 0 0 0 0] vgt -> false -[1 5] [1 4] vgt -> true -[1 5] [1 5 1] vgt -> false - -Diagnostics: -/SyntaxError is raised, if parameters are no valid version number -arrays (see version::validate). - -Author: Ruediger Kupper - -FirstVersion: 29-jul-2003 - -Availability: SLI2.0, library: version - -References: -[1] Ruediger Kupper, SLI library management, - HRI-EU Report 06/05, Honda Research Institute Europe GmbH, 2006. - -SeeAlso: version::validate, version::vcmp, version::veq, version::vlt, version::vgt, version::vleq, version::vgeq, version::s2v, version::v2s -*/ - /vgt[/arraytype /arraytype] - { - vcmp +1 eq - } bind def - - -/* BeginDocumentation -Name: version::vleq - "Less or equal" for version number arrays. - -Synopsis: [version1] [version2] vleq -> true | false - -Description: -Compare two version number arrays. The result is - true, if version1 is less than or equal to version2 - false, otherwise - -The common semantics of version numbers is applied, see version::vcmp. - -Parameters: -version{1|2} - Version number arrays (see version::validate and [1]). - -Examples: -[1 5] [1 5 0 0 0 0 0] vleq -> true -[1 5] [1 4] vleq -> false -[1 5] [1 5 1] vleq -> true - -Diagnostics: -/SyntaxError is raised, if parameters are no valid version number -arrays (see version::validate). - -Author: Ruediger Kupper - -FirstVersion: 29-jul-2003 - -Availability: SLI2.0, library: version - -References: -[1] Ruediger Kupper, SLI library management, - HRI-EU Report 06/05, Honda Research Institute Europe GmbH, 2006. - -SeeAlso: version::validate, version::vcmp, version::veq, version::vlt, version::vgt, version::vleq, version::vgeq, version::s2v, version::v2s -*/ - /vleq[/arraytype /arraytype] - { - vcmp +1 neq - } bind def - - -/* BeginDocumentation -Name: version::vgeq - "Greater or equal" for version number arrays. - -Synopsis: [version1] [version2] vgeq -> true | false - -Description: -Compare two version number arrays. The result is - true, if version1 is greater than or equal to version2 - false, otherwise - -The common semantics of version numbers is applied, see version::vcmp. - -Parameters: -version{1|2} - Version number arrays (see version::validate and [1]). - -Examples: -[1 5] [1 5 0 0 0 0 0] vgeq -> true -[1 5] [1 4] vgeq -> true -[1 5] [1 5 1] vgeq -> false - -Diagnostics: -/SyntaxError is raised, if parameters are no valid version number -arrays (see version::validate). - -Author: Ruediger Kupper - -FirstVersion: 29-jul-2003 - -Availability: SLI2.0, library: version - -References: -[1] Ruediger Kupper, SLI library management, - HRI-EU Report 06/05, Honda Research Institute Europe GmbH, 2006. - -SeeAlso: version::validate, version::vcmp, version::veq, version::vlt, version::vgt, version::vleq, version::vgeq, version::s2v, version::v2s -*/ - /vgeq[/arraytype /arraytype] - { - vcmp -1 neq - } bind def - - - - -/* BeginDocumentation -Name: version::s2v - Convert version number string to array. - -Synopsis: (version) s2v -> [version] - -Description: -Converts a version number contained in a string to a version number -array. The string is expected to contain a "usual" dot-separated version -number, e.g. (1.23.5) (no leading "V"). -As one and only exception, the string may also contain a CVS revision -string, e.g. (Revision: 0.8.15). In all other cases, [0] is returned. -For CVS revision strings of not yet checked-in files, [0] is -returned, too. - -Parameters: -(version) - Version number string. See description above. -[version] - Version number array (see version::validate and [1]). - -Examples: -(1.23.5) s2v -> [1 23 5] -(Revision: 9.9) s2v -> [9 9] -(Revision) s2v -> [0] -(v3.5) s2v -> [0] - -Diagnostics: -/SyntaxError is raised, if result is no valid version number -array (see version::validate). - -Author: Ruediger Kupper - -FirstVersion: 29-jul-2003 - -Availability: SLI2.0, library: version - -References: -[1] Ruediger Kupper, SLI library management, - HRI-EU Report 06/05, Honda Research Institute Europe GmbH, 2006. - -SeeAlso: version::validate, version::vcmp, version::veq, version::vlt, version::vgt, version::vleq, version::vgeq, version::s2v, version::v2s -*/ - /s2v[/stringtype /s] - { - % first, handle possible CVS revision string. There are two possible versions: - - % revision string that has a number: - s ($Revision: ) search - { - %stack: (number $) ($Revision: ) () - pop pop - %stack: (number $) - reverse 0 2 erase reverse - %stack: (number) - } if - - % revision string that has not yet a number: - dup ($Revision) ($) join eq - { - pop - (9999999.9) - M_DEBUG (library::s2v) (Found non-substituted $Revision) ($ string, returning a large number.) join message - M_DEBUG (library::s2v) (Please check that keyword substitution is turned on for this file.) message - %stack: (number) - } if - - % at this point we assume that it's a normal version number. - (.) breakup {cvi} Map - dup validate - } bind SLIFunctionWrapper - - -/* BeginDocumentation -Name: version::v2s - Convert version number array to string. - -Synopsis: [version] s2v -> (version) - -Description: -Converts a version number array to a version number string. The string -contains the "usual" dot-separated version number, e.g. (1.23.5) (no -leading "V"). - -Parameters: -(version) - Version number string. See description above. -[version] - Version number array (see version::validate and [1]). - -Examples: -[1 23 5] -> (1.23.5) -[1 0 0 0] -> (1.0.0.0) - -Diagnostics: -/SyntaxError is raised, if result is no valid version number -array (see version::validate). - -Author: Ruediger Kupper - -FirstVersion: 29-jul-2003 - -Availability: SLI2.0, library: version - -References: -[1] Ruediger Kupper, SLI library management, - HRI-EU Report 06/05, Honda Research Institute Europe GmbH, 2006. - -SeeAlso: version::validate, version::vcmp, version::veq, version::vlt, version::vgt, version::vleq, version::vgeq, version::s2v, version::v2s -*/ - /v2s[/arraytype /v] - { - v validate - v 0 get cvs % get first number - v 0 1 erase % get all other numbers - {cvs (.) exch join join} forall - } bind SLIFunctionWrapper - -end % namespace - diff --git a/libnestutil/Makefile.am b/libnestutil/Makefile.am index e2a0ac63a2..cd8919c1fe 100644 --- a/libnestutil/Makefile.am +++ b/libnestutil/Makefile.am @@ -24,7 +24,6 @@ libnestutil_la_SOURCES= \ libc_allocator_with_realloc.h \ hashtable-common.h \ sparsetable.h \ - connection_generator.h connection_generator.cpp \ compose.hpp diff --git a/libnestutil/allocator.h b/libnestutil/allocator.h index 5d21716b0b..fb8ce9039c 100644 --- a/libnestutil/allocator.h +++ b/libnestutil/allocator.h @@ -181,4 +181,5 @@ namespace sli { } } + #endif diff --git a/libnestutil/connection_generator.cpp b/libnestutil/connection_generator.cpp deleted file mode 100644 index 722d42362c..0000000000 --- a/libnestutil/connection_generator.cpp +++ /dev/null @@ -1,73 +0,0 @@ -/* - * connection_generator.cpp - * - * This file is part of NEST. - * - * Copyright (C) 2004 The NEST Initiative - * - * NEST 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 2 of the License, or - * (at your option) any later version. - * - * NEST 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 NEST. If not, see . - * - */ - -#include "connection_generator.h" - -ConnectionGenerator::~ConnectionGenerator () -{} - - -void -ConnectionGenerator::setMask (Mask& mask) -{ - std::vector m; - m.push_back (mask); - setMask (m, 0); -} - - -void -ConnectionGenerator::setMask (std::vector&, int) -{} - -/** - * Default implementation of size () - */ -int ConnectionGenerator::size () -{ - start (); - int i, j; - double* vals = new double[arity ()]; - int n; - for (n = 0; next (i, j, vals); ++n); - delete[] vals; - return n; -} - -#ifdef CONNECTION_GENERATOR_DEBUG -/** - * Default implementation of size () - */ -class DummyGenerator : public ConnectionGenerator { -public: - int arity () { return 2; } - void setMask (std::vector&, int) { } - void start () { } - bool next (int&, int&, double*) { return false; } -}; - -ConnectionGenerator* makeDummyConnectionGenerator () -{ - return new DummyGenerator (); -} - -#endif diff --git a/libnestutil/connection_generator.h b/libnestutil/connection_generator.h deleted file mode 100644 index 43090a31fc..0000000000 --- a/libnestutil/connection_generator.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * connection_generator.h - * - * This file is part of NEST. - * - * Copyright (C) 2004 The NEST Initiative - * - * NEST 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 2 of the License, or - * (at your option) any later version. - * - * NEST 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 NEST. If not, see . - * - */ - -#ifndef CONNECTION_GENERATOR_H -#define CONNECTION_GENERATOR_H - -#define CONNECTION_GENERATOR_DEBUG 1 - -#include - -/** - * Pure abstract base class for connection generators. - */ -class ConnectionGenerator { - public: - class ClosedInterval { - public: - ClosedInterval (int _first, int _last) : first (_first), last (_last) { } - int first; - int last; - }; - - class IntervalSet { - std::vector ivals; - int _skip; - public: - IntervalSet (int skip = 1) : ivals (), _skip (skip) { } - typedef std::vector::iterator iterator; - iterator begin () { return ivals.begin (); } - iterator end () { return ivals.end (); } - int skip () { return _skip; } - void setSkip (int skip) { _skip = skip; } - void insert (int first, int last) { - ivals.push_back (ClosedInterval (first, last)); - } - }; - - class Mask { - public: - Mask (int sourceSkip = 1, int targetSkip = 1) - : sources (sourceSkip), targets (targetSkip) { } - IntervalSet sources; - IntervalSet targets; - }; - - virtual ~ConnectionGenerator (); - - /** - * Return the number of values associated with this generator - */ - virtual int arity () = 0; - - /** - * Inform the generator of which source and target indexes exist - * (must always be called before any of the methods below) - * - * skip can be used in round-robin allocation schemes. - */ - virtual void setMask (Mask& mask); - - /** - * For a parallel simulator, we want to know the masks for all ranks - */ - virtual void setMask (std::vector& masks, int local) = 0; - - /** - * Return number of connections represented by this generator - */ - virtual int size (); - - /** - * Start an iteration (must be called before first next) - */ - virtual void start () = 0; - - /** - * Advance to next connection or return false - */ - virtual bool next (int& source, int& target, double* value) = 0; -}; - -#ifdef CONNECTION_GENERATOR_DEBUG -ConnectionGenerator* makeDummyConnectionGenerator (); -#endif - -#endif /* #ifndef CONNECTION_GENERATOR_H */ diff --git a/libnestutil/lockptr.h b/libnestutil/lockptr.h index 18cdfd2a1f..f60230d5ab 100644 --- a/libnestutil/lockptr.h +++ b/libnestutil/lockptr.h @@ -76,6 +76,8 @@ since the user might call delete on the pointer. Thus, lockPTR will "lock" the referenced object and deny all further access. The object can be unlocked by calling the unlock() member. + + Equality for lockPTRs is defined as identity of the data object. */ template @@ -92,7 +94,7 @@ class lockPTR bool locked; // forbid this constructor! - PointerObject(PointerObject const&){assert(false);} + PointerObject(PointerObject const&); public: @@ -125,6 +127,11 @@ class lockPTR ++number_of_references; } + void subReference(size_t s) + { + number_of_references-=s; + } + void removeReference(void) { // assert(number_of_references > 0); @@ -196,10 +203,27 @@ class lockPTR virtual ~lockPTR() { - assert(obj != NULL); - obj->removeReference(); + // std::cout << "~lockPTR"; + + // MD experimental, we use obj==0 to indicate controlled detachment + if (exists()) + obj->removeReference(); } + + // MD, experimental + void detach(void) + { + assert(obj != NULL); + assert(obj->references()-1>0); // somebody must remain do delete + obj->subReference(1); + + //std::cout << "after detach ref: " << obj->references() << std::endl; + + obj=NULL; + } + + lockPTR operator=(const lockPTR&spd) { // assert(obj != NULL); @@ -280,6 +304,17 @@ class lockPTR return (obj->get() == NULL); } + + /* operator==, != + Identity operator. These are inherited by derived types, so they should only be called + by the equals method of the derived class which checks for type identity + or when both classes are known to be bare lockPTR. + + These follow identity semantics rather than equality semantics. + The underlying object should only ever be owned by a single PointerObject + that are shared by lockPTRs, so this is equivalent to comparing the address + of the D objects. + */ bool operator==(const lockPTR& p) const { return (obj == p.obj); @@ -297,6 +332,14 @@ class lockPTR return (obj->get() != NULL); } + //MD, experimental + // this condition should only be false inside a recursive call to a datum with + // self references like the DictionaryDatum + bool exists(void) const //!< returns true if and only if obj != NULL + { + return (obj != NULL); + } + bool islocked(void) const { assert(obj != NULL); diff --git a/librandom/Makefile.am b/librandom/Makefile.am index 21c0adf756..f7a3a50f1a 100644 --- a/librandom/Makefile.am +++ b/librandom/Makefile.am @@ -20,12 +20,12 @@ noinst_PROGRAMS = randomtest noinst_LTLIBRARIES= librandom.la AM_CPPFLAGS= -I$(top_srcdir)/libnestutil\ - -I$(top_srcdir)/nestkernel\ -I$(top_srcdir)/sli\ @GSL_CFLAGS@ @MUSIC_INCLUDE@ @MPI_INCLUDE@ ## sources and headers for librandom librandom_la_SOURCES=\ + librandom_exceptions.h \ exp_randomdev.h \ knuthlfg.h knuthlfg.cpp \ mt19937.h mt19937.cpp \ @@ -36,8 +36,11 @@ librandom_la_SOURCES=\ exp_randomdev.cpp \ gamma_randomdev.h gamma_randomdev.cpp \ normal_randomdev.h normal_randomdev.cpp \ + lognormal_randomdev.h lognormal_randomdev.cpp \ poisson_randomdev.h poisson_randomdev.cpp \ randomdev.h randomdev.cpp \ + clipped_randomdev.h \ + uniform_randomdev.h uniform_randomdev.cpp \ uniformint_randomdev.h uniformint_randomdev.cpp \ gslrandomgen.h gslrandomgen.cpp \ gsl_binomial_randomdev.h gsl_binomial_randomdev.cpp diff --git a/librandom/binomial_randomdev.cpp b/librandom/binomial_randomdev.cpp index cc0d25c9db..c21f9c6f24 100644 --- a/librandom/binomial_randomdev.cpp +++ b/librandom/binomial_randomdev.cpp @@ -33,6 +33,8 @@ #include "binomial_randomdev.h" #include "dictutils.h" +#include "compose.hpp" +#include #include librandom::BinomialRandomDev::BinomialRandomDev(RngPtr r_s, @@ -74,7 +76,7 @@ void librandom::BinomialRandomDev::PrecomputeTable(size_t nmax) } -unsigned long librandom::BinomialRandomDev::uldev(RngPtr rng) const +long librandom::BinomialRandomDev::ldev(RngPtr rng) const { assert(rng.valid()); @@ -91,7 +93,7 @@ unsigned long librandom::BinomialRandomDev::uldev(RngPtr rng) const X = n_+1; while( X > n_) { - X = poisson_dev_.uldev(rng); + X = poisson_dev_.ldev(rng); } //10 @@ -186,13 +188,28 @@ void librandom::BinomialRandomDev::init_() void librandom::BinomialRandomDev::set_status(const DictionaryDatum &d) { - double p_tmp; - if ( updateValue(d, "p", p_tmp) ) - set_p(p_tmp); + double p_new = p_; + const bool p_updated = updateValue(d, "p", p_new); - long n_tmp; - if ( updateValue(d, "n", n_tmp) ) - set_n(n_tmp); + long n_new = n_; + const bool n_updated = updateValue(d, "n", n_new); + + if ( p_new < 0. || 1. < p_new ) + throw BadParameterValue("Binomial RDV: 0 <= p <= 1 required."); + + if ( n_new < 1 ) + throw BadParameterValue("Binomial RDV: n >= 1 required."); + + // Binomial numbers are generated from Poisson numbers. + // To avoid an infinite loop, we limit n to slightly less than + // the maximum possible value for Poisson numbers + const long N_MAX = static_cast(0.998 * std::numeric_limits::max()); + if ( n_new > N_MAX ) + throw BadParameterValue(String::compose("Binomial RDV: N < %1 required.", + static_cast(N_MAX))); + + if ( n_updated || p_updated ) + set_p_n(p_new, n_new); } void librandom::BinomialRandomDev::get_status(DictionaryDatum &d) const diff --git a/librandom/binomial_randomdev.h b/librandom/binomial_randomdev.h index bc7bdd2ea0..4a46e78668 100644 --- a/librandom/binomial_randomdev.h +++ b/librandom/binomial_randomdev.h @@ -109,13 +109,12 @@ class BinomialRandomDev : public RandomDev * way of doing things, although all other compilers * happily live without. */ - using RandomDev::uldev; - - unsigned long uldev(void); //!< draw integer - unsigned long uldev(RngPtr) const; //!< draw integer, threaded - bool has_uldev() const { return true; } + using RandomDev::operator(); + using RandomDev::ldev; + + long ldev(RngPtr) const; //!< draw integer, threaded + bool has_ldev() const { return true; } - double operator()(void); //!< return as double double operator()(RngPtr) const; //!< return as double, threaded //! set distribution parameters from SLI dict @@ -140,24 +139,11 @@ class BinomialRandomDev : public RandomDev }; - inline - double BinomialRandomDev::operator()(void) - { - return static_cast(uldev()); - } - inline double BinomialRandomDev::operator()(RngPtr rthrd) const { - return static_cast(uldev(rthrd)); + return static_cast(ldev(rthrd)); } - - inline - unsigned long BinomialRandomDev::uldev(void) - { - return uldev(rng_); - } - } #endif diff --git a/librandom/clipped_randomdev.h b/librandom/clipped_randomdev.h new file mode 100644 index 0000000000..99b4cb6d02 --- /dev/null +++ b/librandom/clipped_randomdev.h @@ -0,0 +1,573 @@ +/* + * clipped_randomdev.h + * + * This file is part of NEST. + * + * Copyright (C) 2004 The NEST Initiative + * + * NEST 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 2 of the License, or + * (at your option) any later version. + * + * NEST 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 NEST. If not, see . + * + */ + +#ifndef CLIPPED_RANDOMDEV_H +#define CLIPPED_RANDOMDEV_H + +#include +#include +#include "randomgen.h" +#include "randomdev.h" +#include "dictutils.h" +#include "sliexceptions.h" +#include "config.h" + +namespace librandom { + +/*BeginDocumentation +Name: rdevdict::*_clipped - clipped random deviate generators. + +Description: Generate random numbers from an underlying distribution, +but restricted to a certain interval. + +For continuous distributions, + + low < random < high + +will hold true, i.e., numbers are restricted to the open interval (low, high). +If the distribution itself is restricted to, e.g., positiv numbers, setting +low < 0 will still only return positive numbers. Clipping only excludes numbers +outside (low, high). + +For discrete distribtions, numbers are limited to {low, low+1, ... high}, i.e., +in this case min and max are included. + +Numbers are clipped by re-drawing any number outside (low, high), until +a number in (log, high) is drawn. The actual distribution of random +numbers drawn will be a distorted version of the underlying +distribution. + +Parameters: +/low lower bound (default: -inf) +/high upper bound (default: +inf) + +Note: +- Clipped generators can be very inefficient if there is little probability +mass in (low, high). +- For continuous distributions, the probability of actually drawing +min or max is approximately 2^-62 ~ 2e-19, i.e., negligible. Therefore, +one can only clip to open intervals. +- There are also *_clipped_to_boundary versions of the generators. These +return the respective boundary value if a value outside the interval is +drawn. These versions are mainly provided to allow reproduction of +publications that used this strategy. + +SeeAlso: CreateRDV, rdevdict +Author: Hans Ekkehard Plesser +*/ + + /** + * Wrapper template turning any continuous RDV into a clipped RDV. + * + * @ingroup RandomDeviateGenerators + * @see ClippedRedrawDiscreteRandomDev + */ + template + class ClippedRedrawContinuousRandomDev : public BaseRDV + { + + public: + + // accept only lockPTRs for initialization, + // otherwise creation of a lock ptr would + // occur as side effect---might be unhealthy + ClippedRedrawContinuousRandomDev(RngPtr); + ClippedRedrawContinuousRandomDev(); // threaded + +#if not defined(HAVE_XLC_ICE_ON_USING) + using RandomDev::operator(); +#endif + + double operator()(void); + double operator()(RngPtr) const; // threaded + + //! set distribution parameters from SLI dict + void set_status(const DictionaryDatum&); + + //! get distribution parameters from SLI dict + void get_status(DictionaryDatum&) const; + + private: + double min_; //!< lower bound + double max_; //!< upper bound + + }; + + template + ClippedRedrawContinuousRandomDev::ClippedRedrawContinuousRandomDev(RngPtr r): + BaseRDV(r), + min_(-std::numeric_limits::infinity()), + max_(std::numeric_limits::infinity()) + { + assert(not BaseRDV::has_ldev()); // ensure underlying distribution is continuous + } + + template + ClippedRedrawContinuousRandomDev::ClippedRedrawContinuousRandomDev(): + BaseRDV(), + min_(-std::numeric_limits::infinity()), + max_(std::numeric_limits::infinity()) + { + assert(not BaseRDV::has_ldev()); // ensure underlying distribution is continuous + } + + template + void ClippedRedrawContinuousRandomDev::set_status(const DictionaryDatum& d) + { + BaseRDV::set_status(d); + + double new_min = min_; + double new_max = max_; + + updateValue(d, "low", new_min); + updateValue(d, "high", new_max); + + if ( new_min >= new_max ) + throw BadParameterValue("Clipped RDVs require low < high."); + + min_ = new_min; + max_ = new_max; + } + + template + void ClippedRedrawContinuousRandomDev::get_status(DictionaryDatum& d) const + { + BaseRDV::get_status(d); + + def(d, "low", min_); + def(d, "high", max_); + } + + template + inline + double ClippedRedrawContinuousRandomDev::operator()(void) + { + return (*this)(this->rng_); + } + + template + inline + double ClippedRedrawContinuousRandomDev::operator()(RngPtr r) const + { + double value; + + do { + value = BaseRDV::operator()(r); + } while ( value <= min_ || max_ <= value ); + + return value; + } + + // ---------------------------------------------------------- + + /** + * Wrapper template turning any discrete RDV into a clipped RDV. + * + * @ingroup RandomDeviateGenerators + * @see ClippedRedrawContinuousRandomDev + */ + template + class ClippedRedrawDiscreteRandomDev : public BaseRDV + { + + public: + + // accept only lockPTRs for initialization, + // otherwise creation of a lock ptr would + // occur as side effect---might be unhealthy + ClippedRedrawDiscreteRandomDev(RngPtr); + ClippedRedrawDiscreteRandomDev(); // threaded + + // Forwarding operators are explicitly defined here, + // to ensure that they forward to the clipped generator. + // Null-pointer checking is done in the underlying generator. + +#if not defined(HAVE_XLC_ICE_ON_USING) + using RandomDev::operator(); + using RandomDev::ldev; +#endif + + double operator()(void); + double operator()(RngPtr) const; // threaded + + long ldev(void); + long ldev(RngPtr) const; + + + //! set distribution parameters from SLI dict + void set_status(const DictionaryDatum&); + + //! get distribution parameters from SLI dict + void get_status(DictionaryDatum&) const; + + private: + long min_; //!< smallest value + long max_; //!< largest value + }; + + template + ClippedRedrawDiscreteRandomDev::ClippedRedrawDiscreteRandomDev(RngPtr r): + BaseRDV(r), + min_(std::numeric_limits::min()), + max_(std::numeric_limits::max()) + { + assert(BaseRDV::has_ldev()); // ensure underlying distribution is discrete + } + + template + ClippedRedrawDiscreteRandomDev::ClippedRedrawDiscreteRandomDev(): + BaseRDV(), + min_(std::numeric_limits::min()), + max_(std::numeric_limits::max()) + { + assert(BaseRDV::has_ldev()); // ensure underlying distribution is discrete + } + + template + void ClippedRedrawDiscreteRandomDev::set_status(const DictionaryDatum& d) + { + BaseRDV::set_status(d); + + long new_min = min_; + long new_max = max_; + + updateValue(d, "low", new_min); + updateValue(d, "high", new_max); + + if ( new_min >= new_max ) + throw BadParameterValue("Clipped RDVs require low < high."); + + min_ = new_min; + max_ = new_max; + } + + template + void ClippedRedrawDiscreteRandomDev::get_status(DictionaryDatum& d) const + { + BaseRDV::get_status(d); + + def(d, "low", min_); + def(d, "high", max_); + } + + template + inline + double ClippedRedrawDiscreteRandomDev::operator()(void) + { + return (*this)(this->rng_); + } + + template + inline + double ClippedRedrawDiscreteRandomDev::operator()(RngPtr r) const + { + double value; + + do { + value = BaseRDV::operator()(r); + } while ( value < min_ || max_ < value ); + + return value; + } + + template + inline + long ClippedRedrawDiscreteRandomDev::ldev(void) + { + return ldev(this->rng_); + } + + template + inline + long ClippedRedrawDiscreteRandomDev::ldev(RngPtr r) const + { + long value; + + do { + value = BaseRDV::ldev(r); + } while ( value < min_ || max_ < value ); + + return value; + } + + // ------------------------------------------------------------------- + + /** + * Wrapper template turning any continuous RDV into a clipped-to-boundary RDV. + * + * To-boundary RDVs return the boundary value if a number outside the + * interval is drawn. This is mainly for reproduction of existing models + * using this approach, it does not make much sense! + + * @ingroup RandomDeviateGenerators + * @see ClippedToBoundaryDiscreteRandomDev + */ + template + class ClippedToBoundaryContinuousRandomDev : public BaseRDV + { + + public: + + // accept only lockPTRs for initialization, + // otherwise creation of a lock ptr would + // occur as side effect---might be unhealthy + ClippedToBoundaryContinuousRandomDev(RngPtr); + ClippedToBoundaryContinuousRandomDev(); // threaded + +#if not defined(HAVE_XLC_ICE_ON_USING) + using RandomDev::operator(); +#endif + + double operator()(void); + double operator()(RngPtr) const; // threaded + + //! set distribution parameters from SLI dict + void set_status(const DictionaryDatum&); + + //! get distribution parameters from SLI dict + void get_status(DictionaryDatum&) const; + + private: + double min_; //!< lower bound + double max_; //!< upper bound + + }; + + template + ClippedToBoundaryContinuousRandomDev::ClippedToBoundaryContinuousRandomDev(RngPtr r): + BaseRDV(r), + min_(-std::numeric_limits::infinity()), + max_(std::numeric_limits::infinity()) + { + assert(not BaseRDV::has_ldev()); // ensure underlying distribution is continuous + } + + template + ClippedToBoundaryContinuousRandomDev::ClippedToBoundaryContinuousRandomDev(): + BaseRDV(), + min_(-std::numeric_limits::infinity()), + max_(std::numeric_limits::infinity()) + { + assert(not BaseRDV::has_ldev()); // ensure underlying distribution is continuous + } + + template + void ClippedToBoundaryContinuousRandomDev::set_status(const DictionaryDatum& d) + { + BaseRDV::set_status(d); + + double new_min = min_; + double new_max = max_; + + updateValue(d, "low", new_min); + updateValue(d, "high", new_max); + + if ( new_min >= new_max ) + throw BadParameterValue("Clipped RDVs require low < high."); + + min_ = new_min; + max_ = new_max; + } + + template + void ClippedToBoundaryContinuousRandomDev::get_status(DictionaryDatum& d) const + { + BaseRDV::get_status(d); + + def(d, "low", min_); + def(d, "high", max_); + } + + template + inline + double ClippedToBoundaryContinuousRandomDev::operator()(void) + { + return (*this)(this->rng_); + } + + template + inline + double ClippedToBoundaryContinuousRandomDev::operator()(RngPtr r) const + { + const double value = BaseRDV::operator()(r); + if ( value < min_ ) + return min_; + if ( value > max_ ) + return max_; + return value; + } + + // ---------------------------------------------------------- + + /** + * Wrapper template turning any discrete RDV into a clipped-to-boundary RDV. + * + * To-boundary RDVs return the boundary value if a number outside the + * interval is drawn. This is mainly for reproduction of existing models + * using this approach, it does not make much sense! + * + * @ingroup RandomDeviateGenerators + * @see ClippedToBoundaryContinuousRandomDev + */ + template + class ClippedToBoundaryDiscreteRandomDev : public BaseRDV + { + + public: + + // accept only lockPTRs for initialization, + // otherwise creation of a lock ptr would + // occur as side effect---might be unhealthy + ClippedToBoundaryDiscreteRandomDev(RngPtr); + ClippedToBoundaryDiscreteRandomDev(); // threaded + + // Forwarding operators are explicitly defined here, + // to ensure that they forward to the clipped generator. + // Null-pointer checking is done in the underlying generator. + +#if not defined(HAVE_XLC_ICE_ON_USING) + using RandomDev::operator(); + using RandomDev::ldev; +#endif + + double operator()(void); + double operator()(RngPtr) const; // threaded + + long ldev(void); + long ldev(RngPtr) const; + + + //! set distribution parameters from SLI dict + void set_status(const DictionaryDatum&); + + //! get distribution parameters from SLI dict + void get_status(DictionaryDatum&) const; + + private: + long min_; //!< smallest value + long max_; //!< largest value + }; + + template + ClippedToBoundaryDiscreteRandomDev::ClippedToBoundaryDiscreteRandomDev(RngPtr r): + BaseRDV(r), + min_(std::numeric_limits::min()), + max_(std::numeric_limits::max()) + { + assert(BaseRDV::has_ldev()); // ensure underlying distribution is discrete + } + + template + ClippedToBoundaryDiscreteRandomDev::ClippedToBoundaryDiscreteRandomDev(): + BaseRDV(), + min_(std::numeric_limits::min()), + max_(std::numeric_limits::max()) + { + assert(BaseRDV::has_ldev()); // ensure underlying distribution is discrete + } + + template + void ClippedToBoundaryDiscreteRandomDev::set_status(const DictionaryDatum& d) + { + BaseRDV::set_status(d); + + long new_min = min_; + long new_max = max_; + + updateValue(d, "low", new_min); + updateValue(d, "high", new_max); + + if ( new_min >= new_max ) + throw BadParameterValue("Clipped RDVs require low < high."); + + min_ = new_min; + max_ = new_max; + } + + template + void ClippedToBoundaryDiscreteRandomDev::get_status(DictionaryDatum& d) const + { + BaseRDV::get_status(d); + + def(d, "low", min_); + def(d, "high", max_); + } + + template + inline + double ClippedToBoundaryDiscreteRandomDev::operator()(void) + { + return (*this)(this->rng_); + } + + template + inline + double ClippedToBoundaryDiscreteRandomDev::operator()(RngPtr r) const + { + const double value = BaseRDV::operator()(r); + if ( value < min_ ) + return min_; + if ( value > max_ ) + return max_; + return value; + } + + template + inline + long ClippedToBoundaryDiscreteRandomDev::ldev(void) + { + return ldev(this->rng_); + } + + template + inline + long ClippedToBoundaryDiscreteRandomDev::ldev(RngPtr r) const + { + const long value = BaseRDV::ldev(r); + if ( value < min_ ) + return min_; + if ( value > max_ ) + return max_; + return value; + } + +} // namespace librandom + +# endif + + + + + + + + + + + + + + + + + + diff --git a/librandom/exp_randomdev.cpp b/librandom/exp_randomdev.cpp index f26a14b2aa..5120ca2086 100644 --- a/librandom/exp_randomdev.cpp +++ b/librandom/exp_randomdev.cpp @@ -20,3 +20,22 @@ * */ #include "exp_randomdev.h" +#include "sliexceptions.h" +#include "dictutils.h" + +void librandom::ExpRandomDev::set_status(const DictionaryDatum& d) +{ + double new_lambda = lambda_; + + updateValue(d, "lambda", new_lambda); + + if ( new_lambda <= 0. ) + throw BadParameterValue("Exponential RDV: lambda > 0 required."); + + lambda_ = new_lambda; +} + +void librandom::ExpRandomDev::get_status(DictionaryDatum& d) const +{ + def(d, "lambda", lambda_); +} diff --git a/librandom/exp_randomdev.h b/librandom/exp_randomdev.h index cddfbf56fb..c74dc8b7e4 100644 --- a/librandom/exp_randomdev.h +++ b/librandom/exp_randomdev.h @@ -34,9 +34,10 @@ namespace librandom { Name: rdevdict::exponential - exponential random deviate generator Description: Generates exponentially distributed random numbers. - p(x) = exp(-x), x >= 0. + p(x) = lambda exp(-lambda*x), x >= 0. -Parameters: No parameters. +Parameters: + lambda - rate parameter (default: 1.0) SeeAlso: CreateRDV, RandomArray, rdevdict Author: Hans Ekkehard Plesser @@ -56,30 +57,26 @@ Author: Hans Ekkehard Plesser // accept only lockPTRs for initialization, // otherwise creation of a lock ptr would // occur as side effect---might be unhealthy - ExpRandomDev(RngPtr r_in) : RandomDev(r_in) {} ; - ExpRandomDev() : RandomDev() {} ; // threaded + ExpRandomDev(RngPtr r_in) : RandomDev(r_in), lambda_(1.0) {} + ExpRandomDev() : RandomDev(), lambda_(1.0) {} // threaded - double operator()(void); // non-threaded + using RandomDev::operator(); double operator()(RngPtr rthrd) const; // threaded //! set distribution parameters from SLI dict - void set_status(const DictionaryDatum&) {} + void set_status(const DictionaryDatum&); //! get distribution parameters from SLI dict - void get_status(DictionaryDatum&) const {} + void get_status(DictionaryDatum&) const; + private: + double lambda_; //!< rate parameter }; - inline - double ExpRandomDev::operator()(void) - { - return -std::log(rng_->drandpos()); - } - inline double ExpRandomDev::operator()(RngPtr rthrd) const { - return -std::log(rthrd->drandpos()); + return -std::log(rthrd->drandpos()) / lambda_; } } diff --git a/librandom/gamma_randomdev.cpp b/librandom/gamma_randomdev.cpp index 3affb1856c..d8a03a95d8 100644 --- a/librandom/gamma_randomdev.cpp +++ b/librandom/gamma_randomdev.cpp @@ -22,26 +22,25 @@ #include "gamma_randomdev.h" #include "dictutils.h" +#include "sliexceptions.h" #include // by default, init as exponential density with mean 1 librandom::GammaRandomDev::GammaRandomDev(RngPtr r_source, double a_in) -: RandomDev(r_source), a(a_in) + : RandomDev(r_source), a(a_in), b_(1.0) { set_order(a); } librandom::GammaRandomDev::GammaRandomDev(double a_in) -: RandomDev(), a(a_in) + : RandomDev(), a(a_in), b_(1.0) { set_order(a); } -double librandom::GammaRandomDev::operator()(RngPtr r) const -{ - assert(r.valid()); // make sure we have RNG - +double librandom::GammaRandomDev::unscaled_gamma(RngPtr r) const +{ // algorithm depends on order a if ( a == 1 ) return -std::log(r->drandpos()); @@ -85,18 +84,28 @@ double librandom::GammaRandomDev::operator()(RngPtr r) const return X; } - } void librandom::GammaRandomDev::set_status(const DictionaryDatum& d) { - double a_tmp; + double a_new = a; + double b_new = b_; + + updateValue(d, "order", a_new); + updateValue(d, "scale", b_new); + + if ( a_new <= 0. ) + throw BadParameterValue("Gamma RDV: order > 0 required."); + + if ( b_new <= 0. ) + throw BadParameterValue("Gamma RDV: scale > 0 required."); - if ( updateValue(d, "order", a_tmp) ) - set_order(a_tmp); + set_order(a_new); + b_ = b_new; } void librandom::GammaRandomDev::get_status(DictionaryDatum &d) const { def(d, "order", a); + def(d, "scale", b_); } diff --git a/librandom/gamma_randomdev.h b/librandom/gamma_randomdev.h index 59772e1e81..3d5d8530bd 100644 --- a/librandom/gamma_randomdev.h +++ b/librandom/gamma_randomdev.h @@ -56,12 +56,11 @@ /* Author: */ /* Hans Ekkehard Plesser */ /* */ -/* References: */ -/* [0] always reserved for Stroustrup */ +/* References: */ +/* [0] always reserved for Stroustrup */ /* [1] L. Devroye, "Non-Uniform Random Variate Generation",*/ /* Springer, 1986 */ /* */ -/* */ /************************************************************/ namespace librandom { @@ -71,14 +70,11 @@ Name: rdevdict::gamma - gamma random deviate generator Description: Generates gamma-distributed random numbers. - gamma(x; order) = x^(order-1) * exp(-x) / Gamma(order) , x >= 0 + gamma(x; order, b) = x^(order-1) * exp(-x/b) / b^order Gamma(order) , x >= 0 Parameters: - order - order of the gamma distribution - -Remarks: - gamma(x; order, b) distributed random number are obtained by - scaling: if X ~ gamma(x; order), then b*X ~ gamma(x; order, b). + order - order of the gamma distribution (default: 1) + b - scale parameter (default: 1) SeeAlso: CreateRDV, RandomArray, rdevdict Author: Hans Ekkehard Plesser @@ -102,6 +98,7 @@ Author: Hans Ekkehard Plesser GammaRandomDev(double a_in = 1.0); //!< create w/o fixed RNG for threaded simulations void set_order(double); //!< set order + void set_scale(double); //!< set scale parameter //! set distribution parameters from SLI dict void set_status(const DictionaryDatum&); @@ -109,27 +106,22 @@ Author: Hans Ekkehard Plesser //! get distribution parameters from SLI dict void get_status(DictionaryDatum&) const; - - double operator()(void); //!< draw number + using RandomDev::operator(); double operator()(RngPtr) const; //!< draw number, threaded double operator()(RngPtr, double); //!< draw number, threaded, explicit order private: + double unscaled_gamma(RngPtr r) const; //! worker function creating Gamma(x; order, 1) number + double a; // gamma density order + double b_; // gamma scale parameter double bb; // parameters b, c of Best's algorithm double bc; double ju; // exponents of U, V of Johnk's algorithm double jv; - }; - inline - double GammaRandomDev::operator()(void) - { - return (*this)(rng_); - } - inline double GammaRandomDev::operator()(RngPtr rthrd, double a) { @@ -137,6 +129,12 @@ Author: Hans Ekkehard Plesser return (*this)(rthrd); } + inline + double GammaRandomDev::operator()(RngPtr r) const + { + return b_ * unscaled_gamma(r); + } + inline void GammaRandomDev::set_order(double a_in=1.0) { diff --git a/librandom/gsl_binomial_randomdev.cpp b/librandom/gsl_binomial_randomdev.cpp index 9117446e4c..b4e24e66a0 100644 --- a/librandom/gsl_binomial_randomdev.cpp +++ b/librandom/gsl_binomial_randomdev.cpp @@ -1,6 +1,23 @@ /* - * Copyright (C) 2012 The NEST Initiative - * This file is part of NEST. + * gsl_binomial_randomdev.cpp + * + * This file is part of NEST. + * + * Copyright (C) 2004 The NEST Initiative + * + * NEST 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 2 of the License, or + * (at your option) any later version. + * + * NEST 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 NEST. If not, see . + * */ #include "gsl_binomial_randomdev.h" @@ -8,12 +25,17 @@ #ifdef HAVE_GSL #include "dictutils.h" +#include "sliexceptions.h" +#include "librandom_exceptions.h" +#include "compose.hpp" +#include librandom::GSL_BinomialRandomDev::GSL_BinomialRandomDev(RngPtr r_s, double p_s, unsigned int n_s) : RandomDev(r_s), p_(p_s), n_(n_s) { GslRandomGen* gsr_rng = dynamic_cast(&(*r_s)); - assert (gsr_rng && "r_s needs to be a GSL RNG"); + if ( !gsr_rng ) + throw UnsuitableRNG("The gsl_binomial RDV can only be used with GSL RNGs."); rng_ = gsr_rng->rng_; } @@ -21,18 +43,25 @@ librandom::GSL_BinomialRandomDev::GSL_BinomialRandomDev(double p_s, unsigned int : RandomDev(), p_(p_s), n_(n_s) {} -unsigned long librandom::GSL_BinomialRandomDev::uldev() +long librandom::GSL_BinomialRandomDev::ldev() { return gsl_ran_binomial(rng_, p_, n_); } -unsigned long librandom::GSL_BinomialRandomDev::uldev(RngPtr rng) const +long librandom::GSL_BinomialRandomDev::ldev(RngPtr rng) const { GslRandomGen* gsr_rng = dynamic_cast(&(*rng)); - assert (gsr_rng && "rng needs to be a GSL RNG"); + if ( !gsr_rng ) + throw UnsuitableRNG("The gsl_binomial RDV can only be used with GSL RNGs."); return gsl_ran_binomial(gsr_rng->rng_, p_, n_); } +void librandom::GSL_BinomialRandomDev::set_p_n(double p_s, unsigned n_s) +{ + set_p(p_s); + set_n(n_s); +} + void librandom::GSL_BinomialRandomDev::set_p(double p_s) { assert( 0.0 <= p_ && p_ <= 1.0 ); @@ -46,13 +75,27 @@ void librandom::GSL_BinomialRandomDev::set_n(unsigned int n_s) void librandom::GSL_BinomialRandomDev::set_status(const DictionaryDatum &d) { - double p_tmp; - if ( updateValue(d, "p", p_tmp) ) - set_p(p_tmp); + double p_new = p_; + const bool p_updated = updateValue(d, "p", p_new); + + long n_new = n_; + const bool n_updated = updateValue(d, "n", n_new); + + if ( p_new < 0. || 1. < p_new ) + throw BadParameterValue("gsl_binomial RDV: 0 <= p <= 1 required."); + + if ( n_new < 1 ) + throw BadParameterValue("gsl_binomial RDV: n >= 1 required."); + + // gsl_ran_binomial() returns unsigned int. To be on the safe side, + // we limit here to within ints. + const long N_MAX = static_cast(0.9 * std::numeric_limits::max()); + if ( n_new > N_MAX ) + throw BadParameterValue(String::compose("Gsl_binomial RDV: N < %1 required.", + static_cast(N_MAX))); - long n_tmp; - if ( updateValue(d, "n", n_tmp) ) - set_n(n_tmp); + if ( n_updated || p_updated ) + set_p_n(p_new, n_new); } void librandom::GSL_BinomialRandomDev::get_status(DictionaryDatum &d) const diff --git a/librandom/gsl_binomial_randomdev.h b/librandom/gsl_binomial_randomdev.h index b434913916..7e56d0ab3e 100644 --- a/librandom/gsl_binomial_randomdev.h +++ b/librandom/gsl_binomial_randomdev.h @@ -1,7 +1,24 @@ /* - Copyright (C) 2012 The NEST Initiative - This file is part of NEST. -*/ + * gsl_binomial_randomdev.h + * + * This file is part of NEST. + * + * Copyright (C) 2004 The NEST Initiative + * + * NEST 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 2 of the License, or + * (at your option) any later version. + * + * NEST 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 NEST. If not, see . + * + */ #include "config.h" @@ -88,13 +105,13 @@ class GSL_BinomialRandomDev : public RandomDev * way of doing things, although all other compilers * happily live without. */ - using RandomDev::uldev; + using RandomDev::operator(); + using RandomDev::ldev; - unsigned long uldev(); //!< draw integer - unsigned long uldev(RngPtr) const; //!< draw integer, threaded - bool has_uldev() const { return true; } + long ldev(); //!< draw integer + long ldev(RngPtr) const; //!< draw integer, threaded + bool has_ldev() const { return true; } - double operator()(); //!< return as double double operator()(RngPtr) const; //!< return as double, threaded //! set distribution parameters from SLI dict @@ -110,16 +127,10 @@ class GSL_BinomialRandomDev : public RandomDev gsl_rng *rng_; }; - inline - double GSL_BinomialRandomDev::operator()() - { - return static_cast(uldev()); - } - inline double GSL_BinomialRandomDev::operator()(RngPtr rthrd) const { - return static_cast(uldev(rthrd)); + return static_cast(ldev(rthrd)); } } diff --git a/librandom/gslrandomgen.cpp b/librandom/gslrandomgen.cpp index 50c86bfa85..59e5d51d8e 100644 --- a/librandom/gslrandomgen.cpp +++ b/librandom/gslrandomgen.cpp @@ -42,7 +42,7 @@ librandom::GslRandomGen::~GslRandomGen() // function initializing RngList // add further self-implemented RNG below -void librandom::GslRandomGen::add_gsl_rngs(DictionaryDatum& rngdict) +void librandom::GslRandomGen::add_gsl_rngs(Dictionary& rngdict) { // add all standard GSL RNG, or those from GSL replacement const gsl_rng_type **t0 = gsl_rng_types_setup(); @@ -51,13 +51,13 @@ void librandom::GslRandomGen::add_gsl_rngs(DictionaryDatum& rngdict) assert(*t != NULL); const std::string name = std::string("gsl_") + (*t)->name; - if ( !rngdict->known( name ) ) // avoid multiple insertion + if ( !rngdict.known( name ) ) // avoid multiple insertion { GslRNGFactory* f = new GslRNGFactory(*t); assert(f != NULL); Token rngfactory = new librandom::RngFactoryDatum(*f); - rngdict->insert_move(Name(name), rngfactory); + rngdict.insert_move(Name(name), rngfactory); } } } diff --git a/librandom/gslrandomgen.h b/librandom/gslrandomgen.h index 462335732e..e8b59a9566 100644 --- a/librandom/gslrandomgen.h +++ b/librandom/gslrandomgen.h @@ -1,5 +1,3 @@ -#ifndef GSLRANDOMGEN_H -#define GSLRANDOMGEN_H /* * gslrandomgen.h * @@ -20,9 +18,16 @@ * You should have received a copy of the GNU General Public License * along with NEST. If not, see . * + */ + +/* * Interface to GSL Random Number Generators * */ + +#ifndef GSLRANDOMGEN_H +#define GSLRANDOMGEN_H + #include #include #include @@ -61,7 +66,7 @@ namespace librandom { ~GslRandomGen(); //! Add all GSL RNGs to rngdict - static void add_gsl_rngs(DictionaryDatum&); + static void add_gsl_rngs(Dictionary&); RngPtr clone(unsigned long s) { @@ -114,32 +119,13 @@ namespace librandom { public: //! Add all GSL RNGs to rngdict //! Do nothing if GSL not available - static void add_gsl_rngs(DictionaryDatum&) {} + static void add_gsl_rngs(Dictionary&) {} private: - GslRandomGen() {assert(false);} - ~GslRandomGen() {assert(false);} - RngPtr clone(unsigned long s) {assert(false);} - - private: - void seed_(unsigned long s); - double drand_(void); - + GslRandomGen() { assert(false); } + ~GslRandomGen() { assert(false); } }; - inline - void GslRandomGen::seed_(unsigned long s) - { - (void) s; //remove warning of unused variable - assert(false); - } - - inline - double GslRandomGen::drand_(void) - { - assert(false); - } - } #endif diff --git a/librandom/knuthlfg.cpp b/librandom/knuthlfg.cpp index df9d1dab68..5cde518459 100644 --- a/librandom/knuthlfg.cpp +++ b/librandom/knuthlfg.cpp @@ -1,3 +1,25 @@ +/* + * knuthlfg.cpp + * + * This file is part of NEST. + * + * Copyright (C) 2004 The NEST Initiative + * + * NEST 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 2 of the License, or + * (at your option) any later version. + * + * NEST 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 NEST. If not, see . + * + */ + /* * Built-in implementation of Knuth's LFG generator. * This code is a C++ adaptation of the code published by Knuth on his diff --git a/librandom/knuthlfg.h b/librandom/knuthlfg.h index 3dfd5b9740..dfd578332a 100644 --- a/librandom/knuthlfg.h +++ b/librandom/knuthlfg.h @@ -1,3 +1,25 @@ +/* + * knuthlfg.h + * + * This file is part of NEST. + * + * Copyright (C) 2004 The NEST Initiative + * + * NEST 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 2 of the License, or + * (at your option) any later version. + * + * NEST 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 NEST. If not, see . + * + */ + #ifndef KNUTHLFG_H #define KNUTHLFG_H diff --git a/librandom/librandom_exceptions.h b/librandom/librandom_exceptions.h new file mode 100644 index 0000000000..c77a84342c --- /dev/null +++ b/librandom/librandom_exceptions.h @@ -0,0 +1,87 @@ +/* + * librandom_exceptions.h + * + * This file is part of NEST. + * + * Copyright (C) 2004 The NEST Initiative + * + * NEST 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 2 of the License, or + * (at your option) any later version. + * + * NEST 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 NEST. If not, see . + * + */ + +#ifndef LIBRANDOM_EXCEPTIONS_H +#define LIBRANDOM_EXCEPTIONS_H + +#include "sliexceptions.h" + +namespace librandom { + + /** + * Exception to be thrown if no (suitable) + * RNG is available. + */ + class MissingRNG: public SLIException + { + std::string msg_; + + public: + + //! @param detailed error message + MissingRNG() + : SLIException("MissingRNG"), + msg_() + {} + + MissingRNG(std::string msg) + : SLIException("MissingRNG"), + msg_(msg) + {} + + ~MissingRNG() throw () {} + + std::string message() { return msg_; } + }; + + /** + * Exception to be thrown if no (suitable) + * RNG is available. + */ + class UnsuitableRNG: public SLIException + { + std::string msg_; + + public: + + //! @param detailed error message + UnsuitableRNG() + : SLIException("UnsuitableRNG"), + msg_() + {} + + UnsuitableRNG(std::string msg) + : SLIException("UnsuitableRNG"), + msg_(msg) + {} + + ~UnsuitableRNG() throw () {} + + std::string message() { return msg_; } + }; + +} + + + + +#endif diff --git a/librandom/lognormal_randomdev.cpp b/librandom/lognormal_randomdev.cpp new file mode 100644 index 0000000000..b81c1021da --- /dev/null +++ b/librandom/lognormal_randomdev.cpp @@ -0,0 +1,86 @@ +/* + * lognormal_randomdev.cpp + * + * This file is part of NEST. + * + * Copyright (C) 2004 The NEST Initiative + * + * NEST 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 2 of the License, or + * (at your option) any later version. + * + * NEST 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 NEST. If not, see . + * + */ + +#include +#include "config.h" +#include "lognormal_randomdev.h" +#include "sliexceptions.h" +#include "dictutils.h" + +// by default, init as exponential density with mean 1 +librandom::LognormalRandomDev::LognormalRandomDev(RngPtr r_source) + : RandomDev(r_source), + mu_(0.), + sigma_(1.) +{} + +// threaded +librandom::LognormalRandomDev::LognormalRandomDev() + : RandomDev(), + mu_(0.), + sigma_(1.) +{} + +void librandom::LognormalRandomDev::set_status(const DictionaryDatum& d) +{ + double new_mu = mu_; + double new_sigma = sigma_; + + updateValue(d, "mu", new_mu); + updateValue(d, "sigma", new_sigma); + + if ( new_sigma < 0. ) + throw BadParameterValue("Lognormal RDV: sigma >= 0 required."); + + mu_ = new_mu; + sigma_ = new_sigma; +} + +void librandom::LognormalRandomDev::get_status(DictionaryDatum& d) const +{ + def(d, "mu", mu_); + def(d, "sigma", sigma_); +} + +double librandom::LognormalRandomDev::operator()(RngPtr r) const +{ + // We could forward here to a NormalRandomDev, but that would + // require keeping such an object. Given that the Box-Muller code + // is short, we just duplicate it here. + + // Box-Muller algorithm, see Knuth TAOCP, vol 2, 3rd ed, p 122 + // we waste one number + double V1; + double V2; + double S; + + do { + V1 = 2 * r->drand() - 1; + V2 = 2 * r->drand() - 1; + S = V1*V1 + V2*V2; + } while ( S >= 1 ); + + if ( S != 0 ) + S = V1 * std::sqrt(-2 * std::log(S)/S); + + return std::exp(mu_ + sigma_ * S); +} diff --git a/librandom/lognormal_randomdev.h b/librandom/lognormal_randomdev.h new file mode 100644 index 0000000000..63081fc5f3 --- /dev/null +++ b/librandom/lognormal_randomdev.h @@ -0,0 +1,104 @@ +/* + * lognormal_randomdev.h + * + * This file is part of NEST. + * + * Copyright (C) 2004 The NEST Initiative + * + * NEST 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 2 of the License, or + * (at your option) any later version. + * + * NEST 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 NEST. If not, see . + * + */ + +#ifndef LOGNORMAL_RANDOMDEV_H +#define LOGNORMAL_RANDOMDEV_H + +#include +#include "randomgen.h" +#include "randomdev.h" +#include "lockptr.h" + + +namespace librandom { + +/*BeginDocumentation +Name: rdevdict::lognormal - lognormal random deviate generator +Description: Generates lognormally distributed random numbers. + + p(x) = 1 / (x * sigma * \sqrt{2 pi}) * exp (-(ln(x)-mu)^2 / 2 sigma^2) + +Parameters: + mu - mean of the underlying normal distribution (default: 0.0) + sigma - standard deviation of the underlying normal distribution (default: 1.0) + +Note: +Mean and variance of the lognormal numbers are given by + + E[X] = exp(mu + sigma^2/2) + Var[X] = (exp(sigma^2) - 1) * E[X]^2 + +SeeAlso: CreateRDV, RandomArray, rdevdict +Author: Hans Ekkehard Plesser +*/ + +/** + * Create lognormal random numbers with uniform variance. + * @ingroup RandomDeviateGenerators + */ + + class LognormalRandomDev : public RandomDev + { + + public: + + // accept only lockPTRs for initialization, + // otherwise creation of a lock ptr would + // occur as side effect---might be unhealthy + LognormalRandomDev(RngPtr); + LognormalRandomDev(); // threaded + + using RandomDev::operator(); + double operator()(RngPtr) const; // threaded + + //! set distribution parameters from SLI dict + void set_status(const DictionaryDatum&); + + //! get distribution parameters from SLI dict + void get_status(DictionaryDatum&) const; + + private: + double mu_; + double sigma_; + }; + +} + +# endif + + + + + + + + + + + + + + + + + + diff --git a/librandom/normal_randomdev.cpp b/librandom/normal_randomdev.cpp index 3c87fd776c..b80b219c0c 100644 --- a/librandom/normal_randomdev.cpp +++ b/librandom/normal_randomdev.cpp @@ -23,17 +23,44 @@ #include #include "config.h" #include "normal_randomdev.h" +#include "sliexceptions.h" +#include "dictutils.h" // by default, init as exponential density with mean 1 librandom::NormalRandomDev::NormalRandomDev(RngPtr r_source) -: RandomDev(r_source) + : RandomDev(r_source), + mu_(0.), + sigma_(1.) {} // threaded librandom::NormalRandomDev::NormalRandomDev() -: RandomDev() + : RandomDev(), + mu_(0.), + sigma_(1.) {} +void librandom::NormalRandomDev::set_status(const DictionaryDatum& d) +{ + double new_mu = mu_; + double new_sigma = sigma_; + + updateValue(d, "mu", new_mu); + updateValue(d, "sigma", new_sigma); + + if ( new_sigma < 0. ) + throw BadParameterValue("Normal RDV: sigma >= 0 required."); + + mu_ = new_mu; + sigma_ = new_sigma; +} + +void librandom::NormalRandomDev::get_status(DictionaryDatum& d) const +{ + def(d, "mu", mu_); + def(d, "sigma", sigma_); +} + double librandom::NormalRandomDev::operator()(RngPtr r) const { // Box-Muller algorithm, see Knuth TAOCP, vol 2, 3rd ed, p 122 @@ -48,8 +75,8 @@ double librandom::NormalRandomDev::operator()(RngPtr r) const S = V1*V1 + V2*V2; } while ( S >= 1 ); - if ( S == 0 ) - return 0; - else - return V1 * std::sqrt(-2 * std::log(S)/S); + if ( S != 0 ) + S = V1 * std::sqrt(-2 * std::log(S)/S); + + return mu_ + sigma_ * S; } diff --git a/librandom/normal_randomdev.h b/librandom/normal_randomdev.h index 2f8c5005fb..691945996c 100644 --- a/librandom/normal_randomdev.h +++ b/librandom/normal_randomdev.h @@ -35,9 +35,11 @@ namespace librandom { Name: rdevdict::normal - normal random deviate generator Description: Generates normally distributed random numbers. - p(x) = 1 / \sqrt{2 pi} * exp (-x^2 / 2) + p(x) = 1 / (sigma * \sqrt{2 pi}) * exp (-(x-mu)^2 / 2 sigma^2) -Parameters: No parameters. +Parameters: + mu - mean (default: 0.0) + sigma - standard deviation (default: 1.0) SeeAlso: CreateRDV, RandomArray, rdevdict Author: Hans Ekkehard Plesser @@ -65,23 +67,20 @@ Author: Hans Ekkehard Plesser NormalRandomDev(RngPtr); NormalRandomDev(); // threaded - double operator()(void); + using RandomDev::operator(); double operator()(RngPtr) const; // threaded //! set distribution parameters from SLI dict - void set_status(const DictionaryDatum&) {} + void set_status(const DictionaryDatum&); //! get distribution parameters from SLI dict - void get_status(DictionaryDatum&) const {} + void get_status(DictionaryDatum&) const; + private: + double mu_; + double sigma_; }; - inline - double NormalRandomDev::operator()(void) - { - return (*this)(rng_); - } - } # endif diff --git a/librandom/poisson_randomdev.cpp b/librandom/poisson_randomdev.cpp index dcf12175c4..7169d5e45c 100644 --- a/librandom/poisson_randomdev.cpp +++ b/librandom/poisson_randomdev.cpp @@ -18,7 +18,9 @@ * You should have received a copy of the GNU General Public License * along with NEST. If not, see . * - * + */ + +/* * Implementation based on J H Ahrens, U Dieter, ACM TOMS 8:163-179(1982) */ @@ -30,6 +32,8 @@ #include "numerics.h" #include "poisson_randomdev.h" #include "dictutils.h" +#include "sliexceptions.h" +#include "compose.hpp" // Poisson CDF tabulation limit for case mu_ < 10, P(46, 10) ~ eps const unsigned librandom::PoissonRandomDev::n_tab_ = 46; @@ -77,10 +81,35 @@ void librandom::PoissonRandomDev::set_lambda(double lambda) void librandom::PoissonRandomDev::set_status(const DictionaryDatum& d) { - double lam; - - if ( updateValue(d, "lambda", lam) ) - set_lambda(lam); + /* + Limits on mu: + + - mu >= 0 trivial + - As shown in comments in ldev(), the maximum absolute value + that can be chosen as a candidate is mu + 710 * sqrt(mu). + - We thus must require mu + 710 * sqrt(mu) < max(long). + - This is equivalent to + + mu < ( 2 N + a^2 - sqrt(4 N + a^2) ) / 2 + + where N is the largest representable integer and a = 710. + - Numerical evaluation shows that mu < 0.999 N is safe for 32 + and 64 bit doubles with a good margin. + */ + + const double MU_MAX = 0.999 * std::numeric_limits::max(); + + double new_mu = mu_; + + if ( updateValue(d, "lambda", new_mu) ) + { + if ( new_mu < 0 ) + throw BadParameterValue("Poisson RDV: lambda >= 0 required."); + if ( new_mu > MU_MAX ) + throw BadParameterValue(String::compose("Poisson RDV: lambda < %1 required.", + MU_MAX)); + set_lambda(new_mu); + } } void librandom::PoissonRandomDev::get_status(DictionaryDatum &d) const @@ -137,7 +166,7 @@ void librandom::PoissonRandomDev::init_() P_[0] = 1.0; // just for safety } -unsigned long librandom::PoissonRandomDev::uldev(RngPtr r) const +long librandom::PoissonRandomDev::ldev(RngPtr r) const { // make sure we have an RNG @@ -161,7 +190,7 @@ unsigned long librandom::PoissonRandomDev::uldev(RngPtr r) const while ( U > P_[K] && K != n_tab_ ) ++K; - return K; + return K; // maximum value: K == n_tab_ == 46 } else { @@ -188,6 +217,12 @@ unsigned long librandom::PoissonRandomDev::uldev(RngPtr r) const } while (T * T > -4.0 * std::log (U)); + /* maximum for T at this point: + + T*T <= -4 ln U ~ -4 * ln 1e-308 ~ 2837 + + => |T| < 54 + */ double G = mu_ + s_ * T; if ( G >= 0 ) { @@ -238,6 +273,13 @@ unsigned long librandom::PoissonRandomDev::uldev(RngPtr r) const U = U + U - 1; T = U >= 0 ? 1.8 + E : 1.8 - E; } while ( T <= -0.6744 ); + + /* maximum for T at this point: + + 0 < E < - ln 1e-308 ~ 709 + + => |T| < 710 + */ // Step H ****************************************************** K = static_cast(std::floor(mu_ + s_ * T)); @@ -252,15 +294,6 @@ unsigned long librandom::PoissonRandomDev::uldev(RngPtr r) const } // mu < 10 - // should never get here, because both branches of the - // if () {} else {} statement above close with the statement - // return K; . Thus, any command following the if construct - // is never executed. The icc 8.0 rightfully detects that our - // original assert(false) generates a "statement is unreachable" - // remark. 30.4.04 Eppler & Diesmann - // - // assert(false); - } void librandom::PoissonRandomDev::proc_f_(const unsigned K, diff --git a/librandom/poisson_randomdev.h b/librandom/poisson_randomdev.h index 5e862967de..2fdb566f00 100644 --- a/librandom/poisson_randomdev.h +++ b/librandom/poisson_randomdev.h @@ -129,13 +129,12 @@ Author: Hans Ekkehard Plesser * way of doing things, although all other compilers * happily live without. */ - using RandomDev::uldev; + using RandomDev::operator(); + using RandomDev::ldev; - unsigned long uldev(void); //!< draw integer - unsigned long uldev(RngPtr) const; //!< draw integer, threaded - bool has_uldev() const { return true; } + long ldev(RngPtr) const; //!< draw integer, threaded + bool has_ldev() const { return true; } - double operator()(void); //!< return as double double operator()(RngPtr) const; //!< return as double, threaded private: @@ -174,23 +173,10 @@ Author: Hans Ekkehard Plesser } - -inline -double librandom::PoissonRandomDev::operator()(void) -{ - return static_cast(uldev()); -} - inline double librandom::PoissonRandomDev::operator()(RngPtr rthrd) const { - return static_cast(uldev(rthrd)); -} - -inline -unsigned long librandom::PoissonRandomDev::uldev(void) -{ - return uldev(rng_); + return static_cast(ldev(rthrd)); } # endif diff --git a/librandom/random_datums.h b/librandom/random_datums.h index e9f405cbcf..0de67c169a 100644 --- a/librandom/random_datums.h +++ b/librandom/random_datums.h @@ -1,5 +1,3 @@ -#ifndef RANDOM_DATUMS_H -#define RANDOM_DATUMS_H /* * random_datums.h * @@ -20,10 +18,16 @@ * You should have received a copy of the GNU General Public License * along with NEST. If not, see . * + */ + +/* * SLI Datum types related to the NEST random library. * */ +#ifndef RANDOM_DATUMS_H +#define RANDOM_DATUMS_H + #include "lockptrdatum.h" #include "random_numbers.h" diff --git a/librandom/random_numbers.cpp b/librandom/random_numbers.cpp index 25d05b6fdc..5184dd7dc4 100644 --- a/librandom/random_numbers.cpp +++ b/librandom/random_numbers.cpp @@ -35,13 +35,16 @@ #include "knuthlfg.h" #include "mt19937.h" #include "gslrandomgen.h" +#include "clipped_randomdev.h" #include "binomial_randomdev.h" #include "poisson_randomdev.h" #include "normal_randomdev.h" #include "exp_randomdev.h" #include "gamma_randomdev.h" +#include "uniform_randomdev.h" #include "uniformint_randomdev.h" +#include "lognormal_randomdev.h" #ifdef HAVE_GSL #include "gsl_binomial_randomdev.h" @@ -57,6 +60,8 @@ template class lockPTRDatum; template class lockPTRDatum; template class lockPTRDatum; +Dictionary* RandomNumbers::rngdict_ = 0; +Dictionary* RandomNumbers::rdvdict_ = 0; RandomNumbers::~RandomNumbers() { @@ -68,19 +73,19 @@ RandomNumbers::~RandomNumbers() } template -void RandomNumbers::register_rng_(const std::string& name, DictionaryDatum& dict) +void RandomNumbers::register_rng_(const std::string& name, Dictionary& dict) { Token rngfactory = new librandom::RngFactoryDatum( new librandom::BuiltinRNGFactory); - dict->insert_move(Name(name), rngfactory); + dict[Name(name)] = rngfactory; } template -void RandomNumbers::register_rdv_(const std::string& name, DictionaryDatum& dict) +void RandomNumbers::register_rdv_(const std::string& name, Dictionary& dict) { Token rdevfactory = new librandom::RdvFactoryDatum( new librandom::RandomDevFactory); - dict->insert_move(Name(name), rdevfactory); + dict.insert_move(Name(name), rdevfactory); } void RandomNumbers::init(SLIInterpreter *i) @@ -96,30 +101,51 @@ void RandomNumbers::init(SLIInterpreter *i) RdvFactoryType.settypename("rdvfactorytype"); RdvFactoryType.setdefaultaction(SLIInterpreter::datatypefunction); + if ( rngdict_ || rdvdict_ ) + throw DynamicModuleManagementError("RandomNumbers module has been initialized previously."); + // create random number generator type dictionary - DictionaryDatum rngdict(new Dictionary()); - i->def("rngdict", rngdict); + rngdict_ = new Dictionary(); + assert(rngdict_); + i->def("rngdict", DictionaryDatum(rngdict_)); // add built-in rngs - register_rng_("knuthlfg", rngdict); - register_rng_("MT19937", rngdict); + register_rng_("knuthlfg", *rngdict_); + register_rng_("MT19937", *rngdict_); // let GslRandomGen add all of the GSL rngs - librandom::GslRandomGen::add_gsl_rngs(rngdict); + librandom::GslRandomGen::add_gsl_rngs(*rngdict_); // create random deviate generator dictionary - DictionaryDatum rdvdict(new Dictionary()); - i->def("rdevdict", rdvdict); - - register_rdv_("binomial", rdvdict); - register_rdv_("poisson", rdvdict); - register_rdv_("normal", rdvdict); - register_rdv_("exponential", rdvdict); - register_rdv_("gamma", rdvdict); - register_rdv_("uniformint", rdvdict); + rdvdict_ = new Dictionary(); + assert(rdvdict_); + i->def("rdevdict", DictionaryDatum(rdvdict_)); + + register_rdv_("binomial", *rdvdict_); + register_rdv_ >("binomial_clipped", *rdvdict_); + register_rdv_ >("binomial_clipped_to_boundary", *rdvdict_); + register_rdv_("poisson", *rdvdict_); + register_rdv_ >("poisson_clipped", *rdvdict_); + register_rdv_ >("poisson_clipped_to_boundary", *rdvdict_); + register_rdv_("uniform", *rdvdict_); + register_rdv_("uniform_int", *rdvdict_); + + register_rdv_("normal", *rdvdict_); + register_rdv_ >("normal_clipped", *rdvdict_); + register_rdv_ >("normal_clipped_to_boundary", *rdvdict_); + register_rdv_("lognormal", *rdvdict_); + register_rdv_ >("lognormal_clipped", *rdvdict_); + register_rdv_ >("lognormal_clipped_to_boundary", *rdvdict_); + + register_rdv_("exponential", *rdvdict_); + register_rdv_ >("exponential_clipped", *rdvdict_); + register_rdv_ >("exponential_clipped_to_boundary", *rdvdict_); + register_rdv_("gamma", *rdvdict_); + register_rdv_ >("gamma_clipped", *rdvdict_); + register_rdv_ >("gamma_clipped_to_boundary", *rdvdict_); #ifdef HAVE_GSL - register_rdv_("gsl_binomial", rdvdict); + register_rdv_("gsl_binomial", *rdvdict_); #endif // create function @@ -141,7 +167,7 @@ void RandomNumbers::init(SLIInterpreter *i) // see librandom.sli for SLI documentation void RandomNumbers::CreateRNGFunction::execute(SLIInterpreter *i) const { - assert(i->OStack.load()>1); + i->assert_stack_load(2); const long seed = getValue(i->OStack.top()); librandom::RngFactoryDatum factory @@ -157,7 +183,7 @@ void RandomNumbers::CreateRNGFunction::execute(SLIInterpreter *i) const // see librandom.sli for SLI documentation void RandomNumbers::CreateRDVFunction::execute(SLIInterpreter *i) const { - assert(i->OStack.load()>1); + i->assert_stack_load(2); librandom::RdvFactoryDatum factory = getValue(i->OStack.top()); @@ -173,86 +199,42 @@ void RandomNumbers::CreateRDVFunction::execute(SLIInterpreter *i) const // see librandom.sli for SLI documentation void RandomNumbers::SetStatus_vdFunction::execute(SLIInterpreter *i) const { - assert(i->OStack.load() > 1); - - DictionaryDatum dict; - librandom::RdvDatum rdv; - - try - { - dict = getValue(i->OStack.top()); - rdv = getValue(i->OStack.pick(1)); - } - catch ( TypeMismatch &e ) - { - i->raiseerror("TypeMismatch"); - return; - } - - try - { - rdv->set_status(dict); - i->OStack.pop(2); - i->EStack.pop(); - } - catch(...) - { - /* This is not nice. Before we improve on this, - we should unify the exception handling in SLI an the kernel, - so that the above set_status can throw a nest::KernelException, - which can be queried here with e.what(). - HEP, 2004-08-05 - */ - i->raiseerror(i->BadErrorHandler); - return; - } + i->assert_stack_load(2); + + DictionaryDatum dict = getValue(i->OStack.top()); + librandom::RdvDatum rdv = getValue(i->OStack.pick(1)); + + dict->clear_access_flags(); + rdv->set_status(dict); + std::string missed; + if ( !dict->all_accessed(missed) ) + throw UnaccessedDictionaryEntry(missed); + + i->OStack.pop(2); + i->EStack.pop(); } // see librandom.sli for SLI documentation void RandomNumbers::GetStatus_vFunction::execute(SLIInterpreter *i) const { - - assert(i->OStack.load() > 0); - - librandom::RdvDatum rdv; - try - { - rdv = getValue(i->OStack.top()); - } - catch ( TypeMismatch &e ) - { - i->raiseerror("TypeMismatch"); - return; - } - - try - { - DictionaryDatum dict(new Dictionary); - assert(dict.valid()); - - rdv->get_status(dict); - - i->OStack.pop(); - i->OStack.push(dict); - i->EStack.pop(); - } - catch(...) - { - /* This is not nice. Before we improve on this, - we should unify the exception handling in SLI an the kernel, - so that the above set_status can throw a nest::KernelException, - which can be queried here with e.what(). - HEP, 2004-08-05 - */ - i->raiseerror(i->BadErrorHandler); - return; - } + i->assert_stack_load(1); + + librandom::RdvDatum rdv = getValue(i->OStack.top()); + + DictionaryDatum dict(new Dictionary); + assert(dict.valid()); + + rdv->get_status(dict); + + i->OStack.pop(); + i->OStack.push(dict); + i->EStack.pop(); } // see librandom.sli for SLI documentation void RandomNumbers::SeedFunction::execute(SLIInterpreter *i) const { - assert(i->OStack.load()>1); + i->assert_stack_load(2); const long seed = getValue(i->OStack.top()); librandom::RngDatum rng = getValue(i->OStack.pick(1)); @@ -266,7 +248,7 @@ void RandomNumbers::SeedFunction::execute(SLIInterpreter *i) const // see librandom.sli for SLI documentation void RandomNumbers::IrandFunction::execute(SLIInterpreter *i) const { - assert(i->OStack.load()>1); + i->assert_stack_load(2); const long N = getValue(i->OStack.top()); librandom::RngDatum rng = getValue(i->OStack.pick(1)); @@ -281,7 +263,7 @@ void RandomNumbers::IrandFunction::execute(SLIInterpreter *i) const // see librandom.sli for SLI documentation void RandomNumbers::DrandFunction::execute(SLIInterpreter *i) const { - assert(i->OStack.load()>0); + i->assert_stack_load(1); librandom::RngDatum rng = getValue(i->OStack.top()); @@ -296,13 +278,7 @@ void RandomNumbers::DrandFunction::execute(SLIInterpreter *i) const /* see librandom.sli for SLI documentation */ void RandomNumbers::RandomArrayFunction::execute(SLIInterpreter *i) const { - if( i->OStack.load() < 2 ) - { - i->message(SLIInterpreter::M_ERROR, "RandomArray","Too few parameters supplied."); - i->message(SLIInterpreter::M_ERROR, "RandomArray","Usage: rdv n RandomArray."); - i->raiseerror(i->StackUnderflowError); - return; - } + i->assert_stack_load(2); librandom::RdvDatum rdv = getValue(i->OStack.pick(1)); const long n = getValue(i->OStack.pick(0)); @@ -310,9 +286,9 @@ void RandomNumbers::RandomArrayFunction::execute(SLIInterpreter *i) const TokenArray result; result.reserve(n); - if ( rdv->has_uldev() ) + if ( rdv->has_ldev() ) for( long j = 0; j < n ; ++j) - result.push_back(rdv->uldev()); + result.push_back(rdv->ldev()); else for( long j=0; jOStack.load()<1 ) - { - i->raiseerror(i->StackUnderflowError); - return; - } + i->assert_stack_load(1); librandom::RdvDatum rdv = getValue(i->OStack.top()); i->OStack.pop(); - if ( rdv->has_uldev() ) - i->OStack.push( rdv->uldev() ); + if ( rdv->has_ldev() ) + i->OStack.push( rdv->ldev() ); else i->OStack.push( (*rdv)() ); i->EStack.pop(); } - - - - diff --git a/librandom/random_numbers.h b/librandom/random_numbers.h index a17bd3faa6..771643b0d7 100644 --- a/librandom/random_numbers.h +++ b/librandom/random_numbers.h @@ -1,6 +1,3 @@ -#ifndef RANDOM_NUMBERS_H -#define RANDOM_NUMBERS_H - /* * random_numbers.h * @@ -23,9 +20,11 @@ * */ +#ifndef RANDOM_NUMBERS_H +#define RANDOM_NUMBERS_H + #include "slitype.h" #include "slimodule.h" -//#include "dictdatum.h" #include @@ -55,22 +54,27 @@ class RandomNumbers: public SLIModule ~RandomNumbers(); const std::string name(void) const - { - return "RandomNumbers"; - } + { + return "RandomNumbers"; + } - const std::string commandstring(void) const - { - return std::string("/librandom /C++ ($Revision: $) provide-component " - "/librandom /SLI (6796) require-component"); - } + const std::string commandstring(void) const + { + return std::string("(librandom) run"); + } /** * Initializes the random number module. * The random number generator * and the random deviate generator dictionaries are set up. */ - void init(SLIInterpreter *); + void init(SLIInterpreter *); + + //! Returns global random number generator dictionary + static const Dictionary& get_rngdict(); + + //! Returns global random deviate generator dictionary + static const Dictionary& get_rdvdict(); // RNG creation function class CreateRNGFunction: public SLIFunction @@ -150,12 +154,28 @@ class RandomNumbers: public SLIModule //! Utility function for registering number generators template - void register_rng_(const std::string& name, DictionaryDatum& dict); + void register_rng_(const std::string& name, Dictionary& dict); //! Utility function for registering deviate generators template - void register_rdv_(const std::string& name, DictionaryDatum& dict); + void register_rdv_(const std::string& name, Dictionary& dict); + static Dictionary* rngdict_; //!< manages random number generators + static Dictionary* rdvdict_; //!< manages random deviate generators }; +inline +const Dictionary& RandomNumbers::get_rngdict() +{ + assert(rngdict_); + return *rngdict_; +} + +inline +const Dictionary& RandomNumbers::get_rdvdict() +{ + assert(rdvdict_); + return *rdvdict_; +} + #endif diff --git a/librandom/randomdev.cpp b/librandom/randomdev.cpp index 47fee6d140..8f0752c8c3 100644 --- a/librandom/randomdev.cpp +++ b/librandom/randomdev.cpp @@ -22,16 +22,7 @@ #include "randomdev.h" -// These two functions must not be inlined -// Otherwise, the Compaq C++ Compiler goes haywire -// HEP, 2004-06-29 -unsigned long librandom::RandomDev::uldev(void) -{ - assert(false); - return 0; -} - -unsigned long librandom::RandomDev::uldev(RngPtr) const +long librandom::RandomDev::ldev(RngPtr) const { assert(false); return 0; diff --git a/librandom/randomdev.h b/librandom/randomdev.h index 96ad9c2d69..cbed3283fb 100644 --- a/librandom/randomdev.h +++ b/librandom/randomdev.h @@ -26,6 +26,7 @@ #include #include "randomgen.h" #include "dictdatum.h" +#include "librandom_exceptions.h" /** * @defgroup RandomDeviateGenerators Random Deviate Generators. @@ -59,7 +60,7 @@ * @note * All RDGs provide double numbers, generators for discrete * distributions may provide unsigned longs as well (eg, Poisson). - * This can be checked with the has_uldev(). + * This can be checked with the has_ldev(). * * @note * Here is a code example for the use of the Poisson generator: @@ -94,7 +95,7 @@ * ... * librandom::RngPtr rng=Node::network()->get_rng(thrd); * ... - * ulong_t n_spikes = poisson_dev_.uldev(rng); + * long_t n_spikes = poisson_dev_.ldev(rng); * ... * } * @endcode @@ -151,19 +152,19 @@ namespace librandom { * of the argument to force all derived classes to implement * both varieties. */ - virtual double operator()(void) = 0; //!< single-threaded + virtual double operator()(void); //!< single-threaded virtual double operator()(RngPtr) const = 0; //!< multi-threaded /** * integer valued functions for discrete distributions */ - virtual unsigned long uldev(void); - virtual unsigned long uldev(RngPtr) const; + virtual long ldev(void); + virtual long ldev(RngPtr) const; /** - * true if RDG implements uldev function + * true if RDG implements ldev function */ - virtual bool has_uldev() const { return false; } + virtual bool has_ldev() const { return false; } //! set RNG void set_rng(RngPtr rng) { rng_ = rng; } @@ -192,15 +193,30 @@ namespace librandom { protected: RngPtr rng_; //!< store underlying RNG - }; + inline + double RandomDev::operator()(void) + { + assert(rng_.valid()); + return (*this)(rng_); + } + + inline + long RandomDev::ldev(void) + { + assert(rng_.valid()); + return this->ldev(rng_); + } + + /** * Generic factory class for RandomDev. */ class GenericRandomDevFactory { public: virtual ~GenericRandomDevFactory() {} + virtual RdvPtr create() const =0; virtual RdvPtr create(RngPtr rng) const =0; }; @@ -213,6 +229,12 @@ namespace librandom { public: + //! create unbound deviate generator + RdvPtr create() const + { + return RdvPtr(new DevType()); + } + //! create deviate generator given uniform number generator RdvPtr create(RngPtr rng) const { diff --git a/librandom/randomgen.h b/librandom/randomgen.h index 044ebe3cf5..443c2212d0 100644 --- a/librandom/randomgen.h +++ b/librandom/randomgen.h @@ -70,7 +70,7 @@ * ... * librandom::RngPtr rng=Node::network()->get_rng(thrd); * ... - * ulong_t n_spikes = poisson_dev_.uldev(rng); + * long_t n_spikes = poisson_dev_.ldev(rng); * ... * } * @endcode diff --git a/librandom/randomtest.cpp b/librandom/randomtest.cpp index 30ab1511b2..5d984cc8d9 100644 --- a/librandom/randomtest.cpp +++ b/librandom/randomtest.cpp @@ -134,7 +134,7 @@ int main(void) register_rng("MT19937", rngdictd); // let GslRandomGen add all of the GSL rngs - librandom::GslRandomGen::add_gsl_rngs(rngdictd); + librandom::GslRandomGen::add_gsl_rngs(rngdict); // run all available RNG std::cout << std::endl diff --git a/librandom/uniform_randomdev.cpp b/librandom/uniform_randomdev.cpp new file mode 100644 index 0000000000..69c05ce563 --- /dev/null +++ b/librandom/uniform_randomdev.cpp @@ -0,0 +1,66 @@ +/* + * uniform_randomdev.cpp + * + * This file is part of NEST. + * + * Copyright (C) 2004 The NEST Initiative + * + * NEST 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 2 of the License, or + * (at your option) any later version. + * + * NEST 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 NEST. If not, see . + * + */ + +#include "uniform_randomdev.h" +#include "dictutils.h" +#include "sliexceptions.h" + +#include + +// by default, init with interval [0, 1) +librandom::UniformRandomDev::UniformRandomDev(RngPtr r_source) + : RandomDev(r_source), + low_(0), + high_(1), + delta_(high_-low_) +{ +} + +librandom::UniformRandomDev::UniformRandomDev() + : RandomDev(), + low_(0), + high_(1), + delta_(high_-low_) +{ +} + +void librandom::UniformRandomDev::set_status(const DictionaryDatum& d) +{ + double new_low = low_; + double new_high = high_; + + updateValue(d, "low", new_low); + updateValue(d, "high", new_high); + + if ( new_high <= new_low ) + throw BadParameterValue("Uniform RDV: low < high required."); + + low_ = new_low; + high_ = new_high; + delta_ = high_ - low_; +} + +void librandom::UniformRandomDev::get_status(DictionaryDatum &d) const +{ + def(d, "low", low_); + def(d, "high", high_); +} diff --git a/librandom/uniform_randomdev.h b/librandom/uniform_randomdev.h new file mode 100644 index 0000000000..33ec87e4e0 --- /dev/null +++ b/librandom/uniform_randomdev.h @@ -0,0 +1,120 @@ +/* + * uniform_randomdev.h + * + * This file is part of NEST. + * + * Copyright (C) 2004 The NEST Initiative + * + * NEST 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 2 of the License, or + * (at your option) any later version. + * + * NEST 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 NEST. If not, see . + * + */ + +#ifndef UNIFORM_RANDOMDEV_H +#define UNIFORM_RANDOMDEV_H + +#include +#include "randomgen.h" +#include "randomdev.h" +#include "lockptr.h" + +/************************************************************/ +/* Class UniformRNG */ +/* */ +/* Generates an RNG which returns integer random numbers */ +/* uniformly distributed between two limits. */ +/* */ +/* Arguments: */ +/* - pointer to an RNG */ +/* */ +/* Author: */ +/* Hans Ekkehard Plesser */ +/* */ +/* History: */ +/* HEP, 2004-08-05 */ +/* */ +/************************************************************/ + +namespace librandom { + +/*BeginDocumentation +Name: rdevdict::uniform - uniform random deviate generator +Description: Generates uniformly distributed numbers in the interval [low, high). + +Parameters: + low - lower interval boundary, included + high - upper interval boudnary, excluded + +SeeAlso: CreateRDV, RandomArray, rdevdict +Author: Hans Ekkehard Plesser +*/ + +/** + * Class UniformRandomDev + * Create uniformly distributed random numbers in [low, high). + * + * @ingroup RandomDeviateGenerators + */ + + class UniformRandomDev : public RandomDev + { + + public: + + // accept only lockPTRs for initialization, + // otherwise creation of a lock ptr would + // occur as side effect---might be unhealthy + UniformRandomDev(RngPtr r_in); + UniformRandomDev(); // threaded + + using RandomDev::operator(); + double operator()(RngPtr rthrd) const; // threaded + + //! set distribution parameters from SLI dict + void set_status(const DictionaryDatum&); + + //! get distribution parameters from SLI dict + void get_status(DictionaryDatum&) const; + + private: + double low_; //!< lower bound, included + double high_; //!< upper bound, excluded + double delta_; //!< interval width + }; + + inline + double UniformRandomDev::operator()(RngPtr rthrd) const + { + return low_ + delta_ * rthrd->drand(); + } + +} +# endif + + + + + + + + + + + + + + + + + + diff --git a/librandom/uniformint_randomdev.cpp b/librandom/uniformint_randomdev.cpp index 11777cb5de..a87943b92e 100644 --- a/librandom/uniformint_randomdev.cpp +++ b/librandom/uniformint_randomdev.cpp @@ -22,9 +22,11 @@ #include "uniformint_randomdev.h" #include "dictutils.h" +#include "sliexceptions.h" +#include "compose.hpp" #include -#include +#include // by default, init as exponential density with mean 1 librandom::UniformIntRandomDev::UniformIntRandomDev(RngPtr r_source) @@ -33,7 +35,6 @@ librandom::UniformIntRandomDev::UniformIntRandomDev(RngPtr r_source) nmax_(0), range_(nmax_-nmin_+1) { - assert(range_ > 0); } librandom::UniformIntRandomDev::UniformIntRandomDev() @@ -42,22 +43,30 @@ librandom::UniformIntRandomDev::UniformIntRandomDev() nmax_(0), range_(nmax_-nmin_+1) { - assert(range_ > 0); } - void librandom::UniformIntRandomDev::set_status(const DictionaryDatum& d) { - updateValue(d, "nmin", nmin_); - updateValue(d, "nmax", nmax_); - range_ = nmax_ - nmin_ + 1; + long new_nmin = nmin_; + long new_nmax = nmax_; + + updateValue(d, "low", new_nmin); + updateValue(d, "high", new_nmax); - if ( range_ < 1 ) - throw std::out_of_range("UniformIntRandomDev::set_status: range >= 1 required."); + if ( new_nmax < new_nmin ) + throw BadParameterValue("Uniformint RDV: low <= high required."); + + if ( new_nmax - new_nmin < 0 ) + throw BadParameterValue(String::compose("Uniformint RDV: high - low < %1 required.", + static_cast(std::numeric_limits::max()))); + + nmin_ = new_nmin; + nmax_ = new_nmax; + range_ = nmax_ - nmin_ + 1; } void librandom::UniformIntRandomDev::get_status(DictionaryDatum &d) const { - def(d, "nmin", nmin_); - def(d, "nmax", nmax_); + def(d, "low", nmin_); + def(d, "high", nmax_); } diff --git a/librandom/uniformint_randomdev.h b/librandom/uniformint_randomdev.h index 8ebd67b26a..68b0af06b5 100644 --- a/librandom/uniformint_randomdev.h +++ b/librandom/uniformint_randomdev.h @@ -48,14 +48,14 @@ namespace librandom { /*BeginDocumentation -Name: rdevdict::uniformint - uniform integer random deviate generator +Name: rdevdict::uniform_int - uniform integer random deviate generator Description: Generates uniformly distributed integers between two given limits - p(n) = 1 / (Nmax - Nmin + 1), n = Nmin, Nmin+1, ..., Nmax + p(n) = 1 / (high - low + 1), n = low, low+1, ..., high Parameters: - Nmin - smallest allowed random number - Nmax - largest allowed random number + low - smallest allowed random number + high - largest allowed random number SeeAlso: CreateRDV, RandomArray, rdevdict Author: Hans Ekkehard Plesser @@ -87,13 +87,12 @@ Author: Hans Ekkehard Plesser * way of doing things, although all other compilers * happily live without. */ - using RandomDev::uldev; + using RandomDev::operator(); + using RandomDev::ldev; - unsigned long uldev(void); //!< draw integer - unsigned long uldev(RngPtr) const; //!< draw integer, threaded - bool has_uldev() const { return true; } + long ldev(RngPtr) const; //!< draw integer, threaded + bool has_ldev() const { return true; } - double operator()(void); // non-threaded double operator()(RngPtr rthrd) const; // threaded //! set distribution parameters from SLI dict @@ -108,27 +107,16 @@ Author: Hans Ekkehard Plesser long range_; //!< nmax_ - nmin_ + 1 }; - inline - double UniformIntRandomDev::operator()(void) - { - return static_cast(uldev()); - } - inline double UniformIntRandomDev::operator()(RngPtr rthrd) const { - return static_cast(uldev(rthrd)); - } - - inline - unsigned long UniformIntRandomDev::uldev(void) - { - return uldev(rng_); + return static_cast(ldev(rthrd)); } inline - unsigned long UniformIntRandomDev::uldev(RngPtr r_s) const + long UniformIntRandomDev::ldev(RngPtr r_s) const { + assert(range_ > 0); return nmin_ + r_s->ulrand(range_); } } diff --git a/models/Makefile.am b/models/Makefile.am index c79d6aba56..6bb101ac13 100644 --- a/models/Makefile.am +++ b/models/Makefile.am @@ -15,10 +15,28 @@ noinst_LTLIBRARIES= libmodelsmodule.la libmodelsmodule_la_CXXFLAGS= @AM_CXXFLAGS@ libmodelsmodule_la_SOURCES= \ - music_event_in_proxy.cpp music_event_in_proxy.h\ - music_event_out_proxy.cpp music_event_out_proxy.h\ - music_cont_in_proxy.cpp music_cont_in_proxy.h\ - music_message_in_proxy.cpp music_message_in_proxy.h\ + ac_generator.h ac_generator.cpp\ + aeif_cond_alpha.h aeif_cond_alpha.cpp\ + aeif_cond_alpha_RK5.h aeif_cond_alpha_RK5.cpp\ + aeif_cond_alpha_multisynapse.h aeif_cond_alpha_multisynapse.cpp\ + aeif_cond_exp.h aeif_cond_exp.cpp\ + binary_neuron.h binary_neuron_impl.h\ + cont_delay_connection.h cont_delay_connection.cpp\ + correlation_detector.h correlation_detector.cpp\ + correlomatrix_detector.h correlomatrix_detector.cpp\ + dc_generator.h dc_generator.cpp\ + gamma_sup_generator.h gamma_sup_generator.cpp\ + ginzburg_neuron.h ginzburg_neuron.cpp\ + hh_cond_exp_traub.h hh_cond_exp_traub.cpp\ + hh_psc_alpha.h hh_psc_alpha.cpp\ + ht_connection.h ht_connection.cpp\ + ht_neuron.h ht_neuron.cpp\ + iaf_chxk_2008.cpp iaf_chxk_2008.h\ + iaf_chs_2007.cpp iaf_chs_2007.h\ + iaf_cond_alpha.h iaf_cond_alpha.cpp\ + iaf_cond_alpha_mc.h iaf_cond_alpha_mc.cpp\ + iaf_cond_exp.h iaf_cond_exp.cpp\ + iaf_cond_exp_sfa_rr.h iaf_cond_exp_sfa_rr.cpp\ iaf_neuron.h iaf_neuron.cpp\ iaf_psc_alpha.h iaf_psc_alpha.cpp\ iaf_psc_alpha_multisynapse.h iaf_psc_alpha_multisynapse.cpp\ @@ -26,52 +44,41 @@ libmodelsmodule_la_SOURCES= \ iaf_psc_delta.h iaf_psc_delta.cpp\ iaf_psc_exp.h iaf_psc_exp.cpp\ iaf_tum_2000.h iaf_tum_2000.cpp\ - iaf_cond_alpha.h iaf_cond_alpha.cpp\ - iaf_cond_exp.h iaf_cond_exp.cpp\ - iaf_cond_exp_sfa_rr.h iaf_cond_exp_sfa_rr.cpp\ - iaf_cond_alpha_mc.cpp iaf_cond_alpha_mc.h\ - aeif_cond_alpha.h aeif_cond_alpha.cpp\ - aeif_cond_exp.h aeif_cond_exp.cpp\ - hh_psc_alpha.h hh_psc_alpha.cpp\ - hh_cond_exp_traub.cpp hh_cond_exp_traub.h\ + izhikevich.h izhikevich.cpp\ mat2_psc_exp.h mat2_psc_exp.cpp\ + mcculloch_pitts_neuron.h mcculloch_pitts_neuron.cpp\ + mip_generator.h mip_generator.cpp\ + modelsmodule.h modelsmodule.cpp\ + multimeter.h multimeter.cpp\ + music_cont_in_proxy.h music_cont_in_proxy.cpp\ + music_event_in_proxy.h music_event_in_proxy.cpp\ + music_event_out_proxy.h music_event_out_proxy.cpp\ + music_message_in_proxy.h music_message_in_proxy.cpp\ + noise_generator.h noise_generator.cpp\ parrot_neuron.h parrot_neuron.cpp\ - pp_psc_delta.h pp_psc_delta.cpp\ - ac_generator.h ac_generator.cpp\ - dc_generator.h dc_generator.cpp\ - spike_generator.h spike_generator.cpp\ poisson_generator.h poisson_generator.cpp\ - noise_generator.h noise_generator.cpp\ - mip_generator.h mip_generator.cpp\ - step_current_generator.h step_current_generator.cpp\ + pp_psc_delta.h pp_psc_delta.cpp\ + pp_pop_psc_delta.h pp_pop_psc_delta.cpp\ + ppd_sup_generator.h ppd_sup_generator.cpp\ pulsepacket_generator.h pulsepacket_generator.cpp\ - ppd_sup_generator.cpp ppd_sup_generator.h\ - gamma_sup_generator.cpp gamma_sup_generator.h\ + quantal_stp_connection.h quantal_stp_connection.cpp\ + sli_neuron.h sli_neuron.cpp\ + sinusoidal_poisson_generator.h sinusoidal_poisson_generator.cpp \ sinusoidal_gamma_generator.h sinusoidal_gamma_generator.cpp \ spike_detector.h spike_detector.cpp\ + spike_generator.h spike_generator.cpp\ spin_detector.h spin_detector.cpp\ - multimeter.cpp multimeter.h\ - correlation_detector.h correlation_detector.cpp\ - volume_transmitter.h volume_transmitter.cpp\ static_connection.h\ static_connection_hom_wd.h\ - cont_delay_connection.h cont_delay_connection.cpp\ - tsodyks_connection.h tsodyks_connection.cpp\ - tsodyks2_connection.h tsodyks2_connection.cpp\ stdp_connection.h stdp_connection.cpp\ - stdp_connection_hom.h stdp_connection_hom.cpp\ stdp_connection_facetshw_hom.h stdp_connection_facetshw_hom.cpp\ - stdp_pl_connection_hom.h stdp_pl_connection_hom.cpp\ + stdp_connection_hom.h stdp_connection_hom.cpp\ stdp_dopa_connection.h stdp_dopa_connection.cpp\ - ht_neuron.cpp ht_neuron.h \ - ht_connection.cpp ht_connection.h \ - sinusoidal_poisson_generator.h sinusoidal_poisson_generator.cpp \ - sli_neuron.cpp sli_neuron.h\ - binary_neuron.h binary_neuron_impl.h\ - ginzburg_neuron.cpp ginzburg_neuron.h\ - mcculloch_pitts_neuron.cpp mcculloch_pitts_neuron.h\ - izhikevich.cpp izhikevich.h\ - modelsmodule.h modelsmodule.cpp + stdp_pl_connection_hom.h stdp_pl_connection_hom.cpp\ + step_current_generator.h step_current_generator.cpp\ + tsodyks2_connection.h tsodyks2_connection.cpp\ + tsodyks_connection.h tsodyks_connection.cpp\ + volume_transmitter.h volume_transmitter.cpp AM_CPPFLAGS= -I$(top_srcdir)/libnestutil\ -I$(top_srcdir)/librandom\ diff --git a/models/ac_generator.h b/models/ac_generator.h index 17221eed77..499f6d701e 100644 --- a/models/ac_generator.h +++ b/models/ac_generator.h @@ -71,7 +71,6 @@ namespace nest{ bool has_proxies() const {return false;} - port check_connection(Connection&, port); void get_status(DictionaryDatum &) const; @@ -140,7 +139,6 @@ namespace nest{ return c.get_target()->connect_sender(e, receptor_type); } - inline void ac_generator::get_status(DictionaryDatum &d) const { diff --git a/models/aeif_cond_alpha.h b/models/aeif_cond_alpha.h index 8f12ba7da1..9bb54fa6af 100644 --- a/models/aeif_cond_alpha.h +++ b/models/aeif_cond_alpha.h @@ -316,7 +316,7 @@ namespace nest static RecordablesMap recordablesMap_; }; - inline + inline port aeif_cond_alpha::check_connection(Connection& c, port receptor_type) { SpikeEvent e; @@ -332,7 +332,7 @@ namespace nest throw UnknownReceptorType(receptor_type, get_name()); return 0; } - + inline port aeif_cond_alpha::connect_sender(CurrentEvent&, port receptor_type) { @@ -343,7 +343,7 @@ namespace nest inline port aeif_cond_alpha::connect_sender(DataLoggingRequest& dlr, - port receptor_type) + port receptor_type) { if (receptor_type != 0) throw UnknownReceptorType(receptor_type, get_name()); diff --git a/models/aeif_cond_alpha_RK5.cpp b/models/aeif_cond_alpha_RK5.cpp new file mode 100644 index 0000000000..ba3aed0d82 --- /dev/null +++ b/models/aeif_cond_alpha_RK5.cpp @@ -0,0 +1,512 @@ +/* + * aeif_cond_alpha_RK5.cpp + * + * This file is part of NEST. + * + * Copyright (C) 2004 The NEST Initiative + * + * NEST 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 2 of the License, or + * (at your option) any later version. + * + * NEST 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 NEST. If not, see . + * + */ + +#include "nest_names.h" +#include "aeif_cond_alpha_RK5.h" +#include "universal_data_logger_impl.h" + +#include "exceptions.h" +#include "network.h" +#include "dict.h" +#include "integerdatum.h" +#include "doubledatum.h" +#include "dictutils.h" +#include "numerics.h" +#include + +#include +#include +#include +#include + +/* ---------------------------------------------------------------- + * Recordables map + * ---------------------------------------------------------------- */ + +nest::RecordablesMap nest::aeif_cond_alpha_RK5::recordablesMap_; + +namespace nest // template specialization must be placed in namespace +{ + // Override the create() method with one call to RecordablesMap::insert_() + // for each quantity to be recorded. + template <> + void RecordablesMap::create() + { + // use standard names whereever you can for consistency! + insert_(names::V_m, + &aeif_cond_alpha_RK5::get_y_elem_); + insert_(names::g_ex, + &aeif_cond_alpha_RK5::get_y_elem_); + insert_(names::g_in, + &aeif_cond_alpha_RK5::get_y_elem_); + insert_(names::w, + &aeif_cond_alpha_RK5::get_y_elem_); + } +} + + +/* ---------------------------------------------------------------- + * Default constructors defining default parameters and state + * ---------------------------------------------------------------- */ + +nest::aeif_cond_alpha_RK5::Parameters_::Parameters_() + : V_peak_ ( 0.0 ), // mV, should not be larger that V_th+10 + V_reset_ (-60.0 ), // mV + t_ref_ ( 0.0 ), // ms + g_L ( 30.0 ), // nS + C_m (281.0 ), // pF + E_ex ( 0.0 ), // mV + E_in (-85.0 ), // mV + E_L (-70.6 ), // mV + Delta_T ( 2.0 ), // mV + tau_w (144.0 ), // ms + a ( 4.0 ), // nS + b ( 80.5 ), // pA + V_th (-50.4 ), // mV + tau_syn_ex ( 0.2 ), // ms + tau_syn_in ( 2.0 ), // ms + I_e ( 0.0 ), // pA + MAXERR (1.0e-10 ), // mV + HMIN (1.0e-3) // ms +{ +} + +nest::aeif_cond_alpha_RK5::State_::State_(const Parameters_& p) + : r_(0) +{ + y_[0] = p.E_L; + for ( size_t i = 1 ; i < STATE_VEC_SIZE ; ++i ) + y_[i] = 0.0; +} + +nest::aeif_cond_alpha_RK5::State_::State_(const State_& s) + : r_(s.r_) +{ + for ( size_t i = 0 ; i < STATE_VEC_SIZE ; ++i ) + y_[i] = s.y_[i]; +} + +nest::aeif_cond_alpha_RK5::State_& nest::aeif_cond_alpha_RK5::State_::operator=(const State_& s) +{ + assert(this != &s); // would be bad logical error in program + + for ( size_t i = 0 ; i < STATE_VEC_SIZE ; ++i ) + y_[i] = s.y_[i]; + r_ = s.r_; + return *this; +} + +/* ---------------------------------------------------------------- + * Parameter and state extractions and manipulation functions + * ---------------------------------------------------------------- */ + +void nest::aeif_cond_alpha_RK5::Parameters_::get(DictionaryDatum &d) const +{ + def(d,names::C_m, C_m); + def(d,names::V_th, V_th); + def(d,names::t_ref, t_ref_); + def(d,names::g_L, g_L); + def(d,names::E_L, E_L); + def(d,names::V_reset,V_reset_); + def(d,names::E_ex, E_ex); + def(d,names::E_in, E_in); + def(d,names::tau_syn_ex, tau_syn_ex); + def(d,names::tau_syn_in, tau_syn_in); + def(d,names::a, a); + def(d,names::b, b); + def(d,names::Delta_T,Delta_T); + def(d,names::tau_w, tau_w); + def(d,names::I_e, I_e); + def(d,names::V_peak, V_peak_); + def(d,names::MAXERR, MAXERR); + def(d,names::HMIN, HMIN); + +} + +void nest::aeif_cond_alpha_RK5::Parameters_::set(const DictionaryDatum& d) +{ + double tmp=0.0; + + updateValue(d,names::V_th, V_th); + updateValue(d,names::V_peak, V_peak_); + updateValue(d,names::t_ref, t_ref_); + updateValue(d,names::E_L, E_L); + updateValue(d,names::V_reset, V_reset_); + updateValue(d,names::E_ex, E_ex); + updateValue(d,names::E_in, E_in); + + updateValue(d,names::C_m, C_m); + updateValue(d,names::g_L, g_L); + + updateValue(d,names::tau_syn_ex, tau_syn_ex); + updateValue(d,names::tau_syn_in, tau_syn_in); + + updateValue(d,names::a, a); + updateValue(d,names::b, b); + updateValue(d,names::Delta_T,Delta_T); + updateValue(d,names::tau_w, tau_w); + + updateValue(d,names::I_e, I_e); + + if(updateValue(d,names::MAXERR, tmp)) + { + if(not tmp >0.0) + throw BadProperty("MAXERR must be positive."); + MAXERR=tmp; + } + + if( updateValue(d,names::HMIN, tmp)) + { + if(not (tmp>0.0)) + throw BadProperty("HMIN must be positive."); + HMIN=tmp; + } + + if ( V_peak_ <= V_th ) + throw BadProperty("V_peak must be larger than threshold."); + + if ( V_reset_ >= V_peak_ ) + throw BadProperty("Ensure that: V_reset < V_peak ."); + + if ( C_m <= 0 ) + { + throw BadProperty("Capacitance must be strictly positive."); + } + + if ( t_ref_ < 0 ) + throw BadProperty("Refractory time cannot be negative."); + + if ( tau_syn_ex <= 0 || tau_syn_in <= 0 || tau_w <= 0 ) + throw BadProperty("All time constants must be strictly positive."); + +} + +void nest::aeif_cond_alpha_RK5::State_::get(DictionaryDatum &d) const +{ + def(d,names::V_m, y_[V_M]); + def(d,names::g_ex, y_[G_EXC]); + def(d,names::dg_ex, y_[DG_EXC]); + def(d,names::g_in, y_[G_INH]); + def(d,names::dg_in, y_[DG_INH]); + def(d,names::w, y_[W]); +} + +void nest::aeif_cond_alpha_RK5::State_::set(const DictionaryDatum& d, const Parameters_&) +{ + updateValue(d,names::V_m, y_[V_M]); + updateValue(d,names::g_ex, y_[G_EXC]); + updateValue(d,names::dg_ex, y_[DG_EXC]); + updateValue(d,names::g_in, y_[G_INH]); + updateValue(d,names::dg_in, y_[DG_INH]); + updateValue(d,names::w, y_[W]); + + if ( y_[G_EXC] < 0 || y_[G_INH] < 0 ) + throw BadProperty("Conductances must not be negative."); +} + +nest::aeif_cond_alpha_RK5::Buffers_::Buffers_(aeif_cond_alpha_RK5& n) + : logger_(n) +{ + // Initialization of the remaining members is deferred to + // init_buffers_(). +} + +nest::aeif_cond_alpha_RK5::Buffers_::Buffers_(const Buffers_&, aeif_cond_alpha_RK5& n) + : logger_(n) +{ + // Initialization of the remaining members is deferred to + // init_buffers_(). +} + +/* ---------------------------------------------------------------- + * Default and copy constructor for node, and destructor + * ---------------------------------------------------------------- */ + +nest::aeif_cond_alpha_RK5::aeif_cond_alpha_RK5() + : Archiving_Node(), + P_(), + S_(P_), + B_(*this) +{ + recordablesMap_.create(); +} + +nest::aeif_cond_alpha_RK5::aeif_cond_alpha_RK5(const aeif_cond_alpha_RK5& n) + : Archiving_Node(n), + P_(n.P_), + S_(n.S_), + B_(n.B_, *this) +{ +} + +nest::aeif_cond_alpha_RK5::~aeif_cond_alpha_RK5() +{ +} + +/* ---------------------------------------------------------------- + * Node initialization functions + * ---------------------------------------------------------------- */ + +void nest::aeif_cond_alpha_RK5::init_state_(const Node& proto) +{ + const aeif_cond_alpha_RK5& pr = downcast(proto); + S_ = pr.S_; +} + +void nest::aeif_cond_alpha_RK5::init_buffers_() +{ + B_.spike_exc_.clear(); // includes resize + B_.spike_inh_.clear(); // includes resize + B_.currents_.clear(); // includes resize + Archiving_Node::clear_history(); + + B_.logger_.reset(); + + B_.step_ = Time::get_resolution().get_ms(); + + // We must integrate this model with high-precision to obtain decent results + B_.IntegrationStep_ = std::min(0.01, B_.step_); + + B_.I_stim_ = 0.0; +} + +void nest::aeif_cond_alpha_RK5::calibrate() +{ + B_.logger_.init(); // ensures initialization in case mm connected after Simulate + + V_.g0_ex_ = 1.0 * numerics::e / P_.tau_syn_ex; + V_.g0_in_ = 1.0 * numerics::e / P_.tau_syn_in; + V_.RefractoryCounts_ = Time(Time::ms(P_.t_ref_)).get_steps(); + assert(V_.RefractoryCounts_ >= 0); // since t_ref_ >= 0, this can only fail in error +} + +/* ---------------------------------------------------------------- + * Update and spike handling functions + * ---------------------------------------------------------------- */ + +/** + * Member function updating the neuron state by integrating the ODE. + * @param origin + * @param from + * @param to + */ +void nest::aeif_cond_alpha_RK5::update(Time const & origin, const long_t from, const long_t to) // proceed in time +{ + assert ( to >= 0 && (delay) from < Scheduler::get_min_delay() ); + assert ( from < to ); + assert ( State_::V_M == 0 ); + + for ( long_t lag = from; lag < to; ++lag ) // proceed by stepsize B_.step_ + { + double t = 0.0; // internal time of the integration period + + if ( S_.r_ > 0 ) // decrease remaining refractory steps if non-zero + --S_.r_; + + // numerical integration with adaptive step size control: + // ------------------------------------------------------ + //The numerical integration of the model equations is performed by + // a Dormand-Prince method (5th order Runge-Kutta method with + // adaptive stepsize control) as desribed in William H. Press et + // al., “Adaptive Stepsize Control for Runge-Kuttaâ€, Chapter 17.2 + // in Numerical Recipes (3rd edition, 2007), 910-914. The solver + // itself performs only a single NUMERICAL integration step, + // starting from t and of size B_.IntegrationStep_ (bounded by + // step); the while-loop ensures integration over the whole + // SIMULATION step (0, step] of size B_.step_ if more than one + // integration step is needed due to a small integration stepsize; + // note that (t+IntegrationStep > step) leads to integration over + // (t, step] and afterwards setting t to step, but it does not + // enforce setting IntegrationStep to step-t; this is of advantage + // for a consistent and efficient integration across subsequent + // simulation intervals. + + double_t &h = B_.IntegrationStep_; // numerical integration step + double_t &tend = B_.step_; // end of simulation step + + const double_t &MAXERR = P_.MAXERR; // maximum error + const double_t &HMIN = P_.HMIN; // minimal integration step + + double_t err; + double_t t_return = 0.0; + + while ( t < B_.step_ ) // while not yet reached end of simulation step + { + bool done=false; + + do{ + + if(tend-t< h) // stop integration at end of simulation step + h = tend - t; + + t_return=t+h; //update t + + // k1 = f(told, y) + aeif_cond_alpha_RK5_dynamics(S_.y_,S_.k1); + + // k2 = f(told + h/5, y + h*k1 / 5) + for(int i=0; i < S_.STATE_VEC_SIZE; ++i) + S_.yin[i] = S_.y_[i] + h * S_.k1[i]/5.0; + aeif_cond_alpha_RK5_dynamics(S_.yin,S_.k2); + + // k3 = f(told + 3/10*h, y + 3/40*h*k1 + 9/40*h*k2) + for(int i=0; i < S_.STATE_VEC_SIZE; ++i) + S_.yin[i] = S_.y_[i] + h * ( 3.0/40.0*S_.k1[i] + + 9.0/40.0*S_.k2[i] ); + aeif_cond_alpha_RK5_dynamics(S_.yin,S_.k3); + + // k4 + for(int i=0; i < S_.STATE_VEC_SIZE; ++i) + S_.yin[i] = S_.y_[i] + h * ( 44.0/45.0*S_.k1[i] + - 56.0/15.0*S_.k2[i] + + 32.0/9.0*S_.k3[i] ); + aeif_cond_alpha_RK5_dynamics(S_.yin,S_.k4); + + // k5 + for(int i=0; i < S_.STATE_VEC_SIZE; ++i) + S_.yin[i] = S_.y_[i] + h * ( 19372.0/6561.0*S_.k1[i] + - 25360.0/2187.0*S_.k2[i] + + 64448.0/6561.0*S_.k3[i] + - 212.0/729.0*S_.k4[i] ); + aeif_cond_alpha_RK5_dynamics(S_.yin,S_.k5); + + // k6 + for(int i=0; i < S_.STATE_VEC_SIZE; ++i) + S_.yin[i] = S_.y_[i] + h * ( 9017.0/3168.0*S_.k1[i] + - 355.0/33.0*S_.k2[i] + + 46732.0/5247.0*S_.k3[i] + + 49.0/176.0*S_.k4[i] + - 5103.0/18656.0*S_.k5[i] ); + aeif_cond_alpha_RK5_dynamics(S_.yin,S_.k6); + + // 5th order + for(int i=0; i < S_.STATE_VEC_SIZE; ++i) + S_.ynew[i] = S_.y_[i] + h * ( 35.0/384.0*S_.k1[i] + + 500.0/1113.0*S_.k3[i] + + 125.0/192.0*S_.k4[i] + - 2187.0/6784.0*S_.k5[i] + + 11.0/84.0*S_.k6[i] ); + aeif_cond_alpha_RK5_dynamics(S_.yin,S_.k7); + + // 4th order + for(int i=0; i < S_.STATE_VEC_SIZE; ++i) + { + S_.yref[i] = S_.y_[i] + h * ( 5179.0/57600.0*S_.k1[i] + + 7571.0/16695.0*S_.k3[i] + + 393.0/640.0*S_.k4[i] + - 92097.0/339200.0*S_.k5[i] + + 187.0/2100.0*S_.k6[i] + + 1.0/40.0*S_.k7[i] ); + } + + err = std::fabs(S_.ynew[0] - S_.yref[0]) / MAXERR + 1.0e-200; //error estimate, + //based on different orders for stepsize prediction. Small value added to prevent err==0 + + // The following flag 'done' is needed to ensure that we accept the result + // for h<=HMIN, irrespective of the error. (See below) + + done = (h<=HMIN); // Always exit loop if h was <=HMIN already + + // prediction of next integration stepsize. This step may result in a stepsize below HMIN. + // If this happens, we must + // 1. set the stepsize to HMIN + // 2. compute the result and accept it irrespective of the error, because we cannot + // decrease the stepsize any further. + // the 'done' flag, computed above ensure that the loop is terminated after the + // result was computed. + + h *= 0.98*std::pow(1.0/err,1.0/5.0); + h = std::max(h,HMIN); + + } while( (err > 1.0) and (not done)); //reject step if err > 1 + + for(unsigned int i=0; i 1e6 ) + throw NumericalInstability(get_name()); + + // spikes are handled inside the while-loop + // due to spike-driven adaptation + if ( S_.r_ > 0 ) // if neuron is still in refractory period + S_.y_[State_::V_M] = P_.V_reset_; // clamp it to V_reset + else if ( S_.y_[State_::V_M] >= P_.V_peak_ ) // V_m >= V_peak: spike + { + S_.y_[State_::V_M] = P_.V_reset_; + S_.y_[State_::W] += P_.b; // spike-driven adaptation + S_.r_ = V_.RefractoryCounts_; // initialize refractory steps with refractory period + + set_spiketime(Time::step(origin.get_steps() + lag + 1)); + SpikeEvent se; + network()->send(*this, se, lag); + } + } //while + + + S_.y_[State_::DG_EXC] += B_.spike_exc_.get_value(lag) * V_.g0_ex_; // add incoming spikes + S_.y_[State_::DG_INH] += B_.spike_inh_.get_value(lag) * V_.g0_in_; + + // set new input current + B_.I_stim_ = B_.currents_.get_value(lag); + + // log state data + B_.logger_.record_data(origin.get_steps() + lag); + + } // for-loop +} // function update() + + + +void nest::aeif_cond_alpha_RK5::handle(SpikeEvent & e) +{ + assert(e.get_delay() > 0); + + if(e.get_weight() > 0.0) + B_.spike_exc_.add_value(e.get_rel_delivery_steps(network()->get_slice_origin()), + e.get_weight() * e.get_multiplicity()); + else + B_.spike_inh_.add_value(e.get_rel_delivery_steps(network()->get_slice_origin()), + -e.get_weight() * e.get_multiplicity()); // keep conductances positive + +} + +void nest::aeif_cond_alpha_RK5::handle(CurrentEvent& e) +{ + assert(e.get_delay() > 0); + + const double_t c=e.get_current(); + const double_t w=e.get_weight(); + + // add weighted current; HEP 2002-10-04 + B_.currents_.add_value(e.get_rel_delivery_steps(network()->get_slice_origin()), + w *c); +} + +void nest::aeif_cond_alpha_RK5::handle(DataLoggingRequest& e) +{ + B_.logger_.handle(e); +} + diff --git a/models/aeif_cond_alpha_RK5.h b/models/aeif_cond_alpha_RK5.h new file mode 100644 index 0000000000..11c3890193 --- /dev/null +++ b/models/aeif_cond_alpha_RK5.h @@ -0,0 +1,419 @@ +/* + * aeif_cond_alpha_RK5.h + * + * This file is part of NEST. + * + * Copyright (C) 2004 The NEST Initiative + * + * NEST 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 2 of the License, or + * (at your option) any later version. + * + * NEST 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 NEST. If not, see . + * + */ + +#ifndef AEIF_COND_ALPHA_RK5_H +#define AEIF_COND_ALPHA_RK5_H + +#include "config.h" + +#include "nest.h" +#include "event.h" +#include "archiving_node.h" +#include "ring_buffer.h" +#include "connection.h" +#include "universal_data_logger.h" +#include "recordables_map.h" + +/* BeginDocumentation +Name: aeif_cond_alpha_RK5 - Conductance based exponential integrate-and-fire neuron model according to Brette and Gerstner (2005). + +Description: +aeif_cond_alpha_RK5 is the adaptive exponential integrate and fire neuron according to Brette and Gerstner (2005). +Synaptic conductances are modelled as alpha-functions. + +This implementation uses a 5th order Runge-Kutta solver with adaptive stepsize to integrate +the differential equation (see Numerical Recipes 3rd Edition, Press et al. 2007, Ch. 17.2). + +The membrane potential is given by the following differential equation: +C dV/dt= -g_L(V-E_L)+g_L*Delta_T*exp((V-V_T)/Delta_T)-g_e(t)(V-E_e) -g_i(t)(V-E_i)-w +I_e + +and + +tau_w * dw/dt= a(V-E_L) -w + +Parameters: +The following parameters can be set in the status dictionary. + +Dynamic state variables: + V_m double - Membrane potential in mV + g_ex double - Excitatory synaptic conductance in nS. + dg_ex double - First derivative of g_ex in nS/ms + g_in double - Inhibitory synaptic conductance in nS. + dg_in double - First derivative of g_in in nS/ms. + w double - Spike-adaptation current in pA. + +Membrane Parameters: + C_m double - Capacity of the membrane in pF + t_ref double - Duration of refractory period in ms. + V_reset double - Reset value for V_m after a spike. In mV. + E_L double - Leak reversal potential in mV. + g_L double - Leak conductance in nS. + I_e double - Constant external input current in pA. + +Spike adaptation parameters: + a double - Subthreshold adaptation in nS. + b double - Spike-triggered adaptation in pA. + Delta_T double - Slope factor in mV + tau_w double - Adaptation time constant in ms + V_th double - Spike initiation threshold in mV + V_peak double - Spike detection threshold in mV. + +Synaptic parameters: + E_ex double - Excitatory reversal potential in mV. + tau_syn_ex double - Rise time of excitatory synaptic conductance in ms (alpha function). + E_in double - Inhibitory reversal potential in mV. + tau_syn_in double - Rise time of the inhibitory synaptic conductance in ms (alpha function). + +Numerical integration parameters: + HMIN double - Minimal stepsize for numerical integration in ms (default 0.001ms). + MAXERR double - Error estimate tolerance for adaptive stepsize control (steps accepted if err<=MAXERR). In mV. + Note that the error refers to the difference between the 4th and 5th order RK terms. + Default 1e-10 mV. + +Authors: Stefan Bucher, Marc-Oliver Gewaltig. + +Sends: SpikeEvent + +Receives: SpikeEvent, CurrentEvent, DataLoggingRequest + +References: Brette R and Gerstner W (2005) Adaptive Exponential Integrate-and-Fire Model as + an Effective Description of Neuronal Activity. J Neurophysiol 94:3637-3642 + +SeeAlso: iaf_cond_alpha, aeif_cond_exp, aeif_cond_alpha +*/ + +namespace nest +{ + + class aeif_cond_alpha_RK5: + public Archiving_Node + { + + public: + aeif_cond_alpha_RK5(); + aeif_cond_alpha_RK5(const aeif_cond_alpha_RK5&); + ~aeif_cond_alpha_RK5(); + + /** + * Import sets of overloaded virtual functions. + * We need to explicitly include sets of overloaded + * virtual functions into the current scope. + * According to the SUN C++ FAQ, this is the correct + * way of doing things, although all other compilers + * happily live without. + */ + + using Node::connect_sender; + using Node::handle; + + port check_connection(Connection&, port); + + void handle(SpikeEvent &); + void handle(CurrentEvent &); + void handle(DataLoggingRequest &); + + port connect_sender(SpikeEvent &, port); + port connect_sender(CurrentEvent &, port); + port connect_sender(DataLoggingRequest &, port); + + void get_status(DictionaryDatum &) const; + void set_status(const DictionaryDatum &); + + private: + + void init_state_(const Node& proto); + void init_buffers_(); + void calibrate(); + void update(Time const &, const long_t, const long_t); + + inline + void aeif_cond_alpha_RK5_dynamics (const double*, double*); + + // END Boilerplate function declarations ---------------------------- + + // Friends -------------------------------------------------------- + + // The next two classes need to be friends to access the State_ class/member + friend class RecordablesMap; + friend class UniversalDataLogger; + + + private: + // ---------------------------------------------------------------- + + //! Independent parameters + struct Parameters_ { + double_t V_peak_; //!< Spike detection threshold in mV + double_t V_reset_; //!< Reset Potential in mV + double_t t_ref_; //!< Refractory period in ms + + double_t g_L; //!< Leak Conductance in nS + double_t C_m; //!< Membrane Capacitance in pF + double_t E_ex; //!< Excitatory reversal Potential in mV + double_t E_in; //!< Inhibitory reversal Potential in mV + double_t E_L; //!< Leak reversal Potential (aka resting potential) in mV + double_t Delta_T; //!< Slope faktor in ms. + double_t tau_w; //!< adaptation time-constant in ms. + double_t a; //!< Subthreshold adaptation in nS. + double_t b; //!< Spike-triggered adaptation in pA + double_t V_th; //!< Spike threshold in mV. + double_t t_ref; //!< Refractory period in ms. + double_t tau_syn_ex; //!< Excitatory synaptic rise time. + double_t tau_syn_in; //!< Inhibitory synaptic rise time. + double_t I_e; //!< Intrinsic current in pA. + double_t MAXERR; //!< Maximal error for adaptive stepsize solver + double_t HMIN; //!< Smallest permissible stepsize in ms. + Parameters_(); //!< Sets default parameter values + + void get(DictionaryDatum&) const; //!< Store current values in dictionary + void set(const DictionaryDatum&); //!< Set values from dicitonary + }; + + public: + // ---------------------------------------------------------------- + + /** + * State variables of the model. + * @note Copy constructor and assignment operator required because + * of C-style array. + */ + struct State_ + { + /** + * Enumeration identifying elements in state array State_::y_. + * The state vector is passed as a C array. This enum + * identifies the elements of the vector. It must be public to be + * accessible from the iteration function. + */ + enum StateVecElems + { + V_M = 0, + DG_EXC , // 1 + G_EXC , // 2 + DG_INH , // 3 + G_INH , // 4 + W , // 5 + STATE_VEC_SIZE + }; + + double_t y_[STATE_VEC_SIZE]; //!< neuron state + double_t k1[STATE_VEC_SIZE]; //!< Runge-Kutta variable + double_t k2[STATE_VEC_SIZE]; //!< Runge-Kutta variable + double_t k3[STATE_VEC_SIZE]; //!< Runge-Kutta variable + double_t k4[STATE_VEC_SIZE]; //!< Runge-Kutta variable + double_t k5[STATE_VEC_SIZE]; //!< Runge-Kutta variable + double_t k6[STATE_VEC_SIZE]; //!< Runge-Kutta variable + double_t k7[STATE_VEC_SIZE]; //!< Runge-Kutta variable + double_t yin[STATE_VEC_SIZE]; //!< Runge-Kutta variable + double_t ynew[STATE_VEC_SIZE];//!< 5th order update + double_t yref[STATE_VEC_SIZE];//!< 4th order update + int_t r_; //!< number of refractory steps remaining + + State_(const Parameters_&); //!< Default initialization + State_(const State_&); + State_& operator=(const State_&); + + void get(DictionaryDatum&) const; + void set(const DictionaryDatum&, const Parameters_&); + }; + + // ---------------------------------------------------------------- + + /** + * Buffers of the model. + */ + struct Buffers_ { + Buffers_(aeif_cond_alpha_RK5&); //! logger_; + + /** buffers and sums up incoming spikes/currents */ + RingBuffer spike_exc_; + RingBuffer spike_inh_; + RingBuffer currents_; + + // IntergrationStep_ should be reset with the neuron on ResetNetwork, + // but remain unchanged during calibration. Since it is initialized with + // step_, and the resolution cannot change after nodes have been created, + // it is safe to place both here. + double_t step_; //!< simulation step size in ms + double IntegrationStep_;//!< current integration time step, updated by solver + + /** + * Input current injected by CurrentEvent. + * This variable is used to transport the current applied into the + * _dynamics function computing the derivative of the state vector. + * It must be a part of Buffers_, since it is initialized once before + * the first simulation, but not modified before later Simulate calls. + */ + double_t I_stim_; + }; + + // ---------------------------------------------------------------- + + /** + * Internal variables of the model. + */ + struct Variables_ { + /** initial value to normalise excitatory synaptic conductance */ + double_t g0_ex_; + + /** initial value to normalise inhibitory synaptic conductance */ + double_t g0_in_; + + int_t RefractoryCounts_; + }; + + // Access functions for UniversalDataLogger ------------------------------- + + //! Read out state vector elements, used by UniversalDataLogger + template + double_t get_y_elem_() const { return S_.y_[elem]; } + + // ---------------------------------------------------------------- + + Parameters_ P_; + State_ S_; + Variables_ V_; + Buffers_ B_; + + //! Mapping of recordables names to access functions + static RecordablesMap recordablesMap_; + }; + + inline + port aeif_cond_alpha_RK5::check_connection(Connection& c, port receptor_type) + { + SpikeEvent e; + e.set_sender(*this); + c.check_event(e); + return c.get_target()->connect_sender(e, receptor_type); + } + + inline + port aeif_cond_alpha_RK5::connect_sender(SpikeEvent&, port receptor_type) + { + if (receptor_type != 0) + throw UnknownReceptorType(receptor_type, get_name()); + return 0; + } + + inline + port aeif_cond_alpha_RK5::connect_sender(CurrentEvent&, port receptor_type) + { + if (receptor_type != 0) + throw UnknownReceptorType(receptor_type, get_name()); + return 0; + } + + inline + port aeif_cond_alpha_RK5::connect_sender(DataLoggingRequest& dlr, + port receptor_type) + { + if (receptor_type != 0) + throw UnknownReceptorType(receptor_type, get_name()); + return B_.logger_.connect_logging_device(dlr, recordablesMap_); + } + + inline + void aeif_cond_alpha_RK5::get_status(DictionaryDatum &d) const + { + P_.get(d); + S_.get(d); + Archiving_Node::get_status(d); + + (*d)[names::recordables] = recordablesMap_.get_list(); + } + + inline + void aeif_cond_alpha_RK5::set_status(const DictionaryDatum &d) + { + Parameters_ ptmp = P_; // temporary copy in case of errors + ptmp.set(d); // throws if BadProperty + State_ stmp = S_; // temporary copy in case of errors + stmp.set(d, ptmp); // throws if BadProperty + + // We now know that (ptmp, stmp) are consistent. We do not + // write them back to (P_, S_) before we are also sure that + // the properties to be set in the parent class are internally + // consistent. + Archiving_Node::set_status(d); + + // if we get here, temporaries contain consistent set of properties + P_ = ptmp; + S_ = stmp; + } + +/** + * Function computing right-hand side of ODE for the ODE solver. + * @param y State vector (input). + * @param f Derivatives (output). + */ +inline +void aeif_cond_alpha_RK5::aeif_cond_alpha_RK5_dynamics (const double y[], double f[]) +{ + // a shorthand + typedef aeif_cond_alpha_RK5::State_ S; + + // y[] is the current internal state of the integrator (yin), not the state vector in the node, node.S_.y[]. + + // The following code is verbose for the sake of clarity. We assume that a + // good compiler will optimize the verbosity away ... + + // This constant is used below as the largest admissible value for the exponential spike upstroke + static const double_t largest_exp=std::exp(10.); + + // shorthand for state variables + const double_t& V = y[S::V_M]; + const double_t& dg_ex = y[S::DG_EXC]; + const double_t& g_ex = y[S::G_EXC ]; + const double_t& dg_in = y[S::DG_INH]; + const double_t& g_in = y[S::G_INH ]; + const double_t& w = y[S::W]; + + const double_t I_syn_exc = g_ex * (V - P_.E_ex); + const double_t I_syn_inh = g_in * (V - P_.E_in); + + // We pre-compute the argument of the exponential + const double_t exp_arg=(V - P_.V_th) / P_.Delta_T; + // If the argument is too large, we clip it. + const double_t I_spike = (exp_arg>10.)? largest_exp : P_.Delta_T * std::exp(exp_arg); + + // dv/dt + f[S::V_M ] = ( -P_.g_L *( (V-P_.E_L) - I_spike ) + - I_syn_exc - I_syn_inh - w + P_.I_e + B_.I_stim_) / P_.C_m; + f[S::DG_EXC] = -dg_ex / P_.tau_syn_ex; + f[S::G_EXC ] = dg_ex - g_ex / P_.tau_syn_ex; // Synaptic Conductance (nS) + + f[S::DG_INH] = -dg_in / P_.tau_syn_in; + f[S::G_INH ] = dg_in - g_in / P_.tau_syn_in; // Synaptic Conductance (nS) + + // Adaptation current w. + f[S::W ] = ( P_.a * (V - P_.E_L) - w ) / P_.tau_w; +} + + +} // namespace + +#endif //AEIF_COND_ALPHA_RK5_H diff --git a/models/aeif_cond_alpha_multisynapse.cpp b/models/aeif_cond_alpha_multisynapse.cpp new file mode 100644 index 0000000000..ac3fdc514a --- /dev/null +++ b/models/aeif_cond_alpha_multisynapse.cpp @@ -0,0 +1,680 @@ +/* + * aeif_cond_alpha_multisynapse.cpp + * + * This file is part of NEST. + * + * Copyright (C) 2004 The NEST Initiative + * + * NEST 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 2 of the License, or + * (at your option) any later version. + * + * NEST 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 NEST. If not, see . + * + */ + +#include "exceptions.h" +#include "aeif_cond_alpha_multisynapse.h" +#include "network.h" +#include "dict.h" +#include "integerdatum.h" +#include "doubledatum.h" +#include "dictutils.h" +#include "numerics.h" +#include "universal_data_logger_impl.h" + +#include + +/* ---------------------------------------------------------------- + * Recordables map + * ---------------------------------------------------------------- */ + +nest::RecordablesMap nest::aeif_cond_alpha_multisynapse::recordablesMap_; + +namespace nest +{ +// Override the create() method with one call to RecordablesMap::insert_() +// for each quantity to be recorded. + template<> + void RecordablesMap::create() + { + // use standard names wherever you can for consistency! + insert_(names::V_m, + &aeif_cond_alpha_multisynapse::get_y_elem_< + aeif_cond_alpha_multisynapse::State_::V_M>); + + insert_(names::w, + &aeif_cond_alpha_multisynapse::get_y_elem_< + aeif_cond_alpha_multisynapse::State_::W>); + } + + /* ---------------------------------------------------------------- + * Default constructors defining default parameters and state + * ---------------------------------------------------------------- */ + + aeif_cond_alpha_multisynapse::Parameters_::Parameters_() : + V_peak_(0.0), // mV, should not be larger that V_th+10 + V_reset_(-60.0), // mV + t_ref_(0.0), // ms + g_L(30.0), // nS + C_m(281.0), // pF + E_ex(0.0), // mV + E_in(-85.0), // mV + E_L(-70.6), // mV + Delta_T(2.0), // mV + tau_w(144.0), // ms + a(4.0), // nS + b(80.5), // pA + V_th(-50.4), // mV + I_e(0.0), // pA + MAXERR(1.0e-10), // mV + HMIN(1.0e-3), // ms + has_connections_(false) + { + taus_syn.clear(); + } + + aeif_cond_alpha_multisynapse::State_::State_(const Parameters_& p) : + y_(STATE_VECTOR_MIN_SIZE, 0.0), k1(STATE_VECTOR_MIN_SIZE, 0.0), k2( + STATE_VECTOR_MIN_SIZE, 0.0), k3(STATE_VECTOR_MIN_SIZE, 0.0), k4( + STATE_VECTOR_MIN_SIZE, 0.0), k5(STATE_VECTOR_MIN_SIZE, 0.0), k6( + STATE_VECTOR_MIN_SIZE, 0.0), k7(STATE_VECTOR_MIN_SIZE, 0.0), yin( + STATE_VECTOR_MIN_SIZE, 0.0), ynew(STATE_VECTOR_MIN_SIZE, 0.0), yref( + STATE_VECTOR_MIN_SIZE, 0.0), r_(0) + { + y_[0] = p.E_L; + } + + aeif_cond_alpha_multisynapse::State_::State_(const State_& s) : + r_(s.r_) + { + y_ = s.y_; + k1 = s.k1; + k2 = s.k2; + k3 = s.k3; + k4 = s.k4; + k5 = s.k5; + k6 = s.k6; + k7 = s.k7; + yin = s.yin; + ynew = s.ynew; + yref = s.yref; + } + + aeif_cond_alpha_multisynapse::State_& aeif_cond_alpha_multisynapse::State_::operator=( + const State_& s) + { + assert(this != &s); // would be bad logical error in program + y_ = s.y_; + k1 = s.k1; + k2 = s.k2; + k3 = s.k3; + k4 = s.k4; + k5 = s.k5; + k6 = s.k6; + k7 = s.k7; + yin = s.yin; + ynew = s.ynew; + yref = s.yref; + r_ = s.r_; + return *this; + } + + /* ---------------------------------------------------------------- + * Parameter and state extractions and manipulation functions + * ---------------------------------------------------------------- */ + + void aeif_cond_alpha_multisynapse::Parameters_::get(DictionaryDatum &d) const + { + def(d, names::C_m, C_m); + def(d, names::V_th, V_th); + def(d, names::t_ref, t_ref_); + def(d, names::g_L, g_L); + def(d, names::E_L, E_L); + def(d, names::V_reset, V_reset_); + def(d, names::E_ex, E_ex); + def(d, names::E_in, E_in); + ArrayDatum taus_syn_ad(taus_syn); + def(d, names::taus_syn, taus_syn_ad); + def(d, names::a, a); + def(d, names::b, b); + def(d, names::Delta_T, Delta_T); + def(d, names::tau_w, tau_w); + def(d, names::I_e, I_e); + def(d, names::V_peak, V_peak_); + def(d, names::MAXERR, MAXERR); + def(d, names::HMIN, HMIN); + def(d, "n_synapses", num_of_receptors_); + def(d, names::has_connections, has_connections_); + } + + void aeif_cond_alpha_multisynapse::Parameters_::set(const DictionaryDatum& d) + { + double tmp = 0.0; + + updateValue(d, names::V_th, V_th); + updateValue(d, names::V_peak, V_peak_); + updateValue(d, names::t_ref, t_ref_); + updateValue(d, names::E_L, E_L); + updateValue(d, names::V_reset, V_reset_); + updateValue(d, names::E_ex, E_ex); + updateValue(d, names::E_in, E_in); + + updateValue(d, names::C_m, C_m); + updateValue(d, names::g_L, g_L); + + std::vector tau_tmp; + if (updateValue >(d, names::taus_syn, tau_tmp)) + { + for (size_t i = 0; i < tau_tmp.size(); ++i) + { + if (tau_tmp.size() < taus_syn.size() && has_connections_ == true) + { + throw BadProperty( + "The neuron has connections, therefore the number of ports cannot be reduced."); + } + else if (tau_tmp[i] <= 0) + { + throw BadProperty( + "All synaptic time constants must be strictly positive"); + } + } + taus_syn = tau_tmp; + num_of_receptors_ = taus_syn.size(); + } + + updateValue(d, names::a, a); + updateValue(d, names::b, b); + updateValue(d, names::Delta_T, Delta_T); + updateValue(d, names::tau_w, tau_w); + + updateValue(d, names::I_e, I_e); + + if (updateValue(d, names::MAXERR, tmp)) + { + if (not tmp > 0.0) + { + throw BadProperty("MAXERR must be positive."); + } + MAXERR = tmp; + } + + if (updateValue(d, names::HMIN, tmp)) + { + if (not (tmp > 0.0)) + { + throw BadProperty("HMIN must be positive."); + } + HMIN = tmp; + } + + if (V_peak_ <= V_th) + { + throw BadProperty("V_peak must be larger than threshold."); + } + + if (V_reset_ >= V_peak_) + { + throw BadProperty("Ensure that: V_reset < V_peak ."); + } + + if (C_m <= 0) + { + throw BadProperty("Capacitance must be strictly positive."); + } + + if (t_ref_ < 0) + { + throw BadProperty("Refractory time cannot be negative."); + } + + if (tau_w <= 0) + { + throw BadProperty("All time constants must be strictly positive."); + } + } + + void aeif_cond_alpha_multisynapse::State_::get(DictionaryDatum& d) const + { + def(d, names::V_m, y_[V_M]); + + std::vector* g_exc = new std::vector(); + std::vector* dg_exc = new std::vector(); + std::vector* g_inh = new std::vector(); + std::vector* dg_inh = new std::vector(); + + for (size_t i = 0; + i + < ((y_.size() - State_::NUMBER_OF_FIXED_STATES_ELEMENTS) + / State_::NUMBER_OF_STATES_ELEMENTS_PER_RECEPTOR); ++i) + { + g_exc->push_back( + y_[State_::G_EXC + + (State_::NUMBER_OF_STATES_ELEMENTS_PER_RECEPTOR * i)]); + dg_exc->push_back( + y_[State_::DG_EXC + + (State_::NUMBER_OF_STATES_ELEMENTS_PER_RECEPTOR * i)]); + g_inh->push_back( + y_[State_::G_INH + + (State_::NUMBER_OF_STATES_ELEMENTS_PER_RECEPTOR * i)]); + dg_inh->push_back( + y_[State_::DG_INH + + (State_::NUMBER_OF_STATES_ELEMENTS_PER_RECEPTOR * i)]); + } + + (*d)[names::g_ex] = DoubleVectorDatum(g_exc); + (*d)[names::dg_ex] = DoubleVectorDatum(dg_exc); + (*d)[names::g_in] = DoubleVectorDatum(g_inh); + (*d)[names::dg_in] = DoubleVectorDatum(dg_inh); + + def(d, names::w, y_[W]); + } + + void aeif_cond_alpha_multisynapse::State_::set(const DictionaryDatum& d) + { + updateValue(d, names::V_m, y_[V_M]); + + if ((d->known(names::g_ex)) && (d->known(names::dg_ex)) + && (d->known(names::g_in)) && (d->known(names::dg_in))) + { + const std::vector g_exc = getValue >( + d->lookup(names::g_ex)); + const std::vector dg_exc = getValue >( + d->lookup(names::dg_ex)); + const std::vector g_inh = getValue >( + d->lookup(names::g_in)); + const std::vector dg_inh = getValue >( + d->lookup(names::dg_in)); + + if ((g_exc.size() != dg_exc.size()) || (g_exc.size() != g_inh.size()) + || (g_exc.size() != dg_inh.size())) + { + throw BadProperty("Conductances must have the same sizes."); + } + + for (size_t i = 0; i < g_exc.size(); ++i) + { + if ((g_exc[i] < 0) || (dg_exc[i] < 0) || (g_inh[i] < 0) + || (dg_inh[i] < 0)) + { + throw BadProperty("Conductances must not be negative."); + } + + y_[State_::G_EXC + (State_::NUMBER_OF_STATES_ELEMENTS_PER_RECEPTOR * i)] = + g_exc[i]; + y_[State_::DG_EXC + (State_::NUMBER_OF_STATES_ELEMENTS_PER_RECEPTOR * i)] = + dg_exc[i]; + y_[State_::G_INH + (State_::NUMBER_OF_STATES_ELEMENTS_PER_RECEPTOR * i)] = + g_inh[i]; + y_[State_::DG_INH + (State_::NUMBER_OF_STATES_ELEMENTS_PER_RECEPTOR * i)] = + dg_inh[i]; + } + } + + updateValue(d, names::w, y_[W]); + } + + aeif_cond_alpha_multisynapse::Buffers_::Buffers_( + aeif_cond_alpha_multisynapse& n) : + logger_(n) + { + } + + aeif_cond_alpha_multisynapse::Buffers_::Buffers_(const Buffers_ &, + aeif_cond_alpha_multisynapse& n) : + logger_(n) + { + } + + /* ---------------------------------------------------------------- + * Default and copy constructor for node, and destructor + * ---------------------------------------------------------------- */ + + aeif_cond_alpha_multisynapse::aeif_cond_alpha_multisynapse() : + Archiving_Node(), P_(), S_(P_), B_(*this) + { + recordablesMap_.create(); + } + + aeif_cond_alpha_multisynapse::aeif_cond_alpha_multisynapse( + const aeif_cond_alpha_multisynapse& n) : + Archiving_Node(n), P_(n.P_), S_(n.S_), B_(n.B_, *this) + { + } + + aeif_cond_alpha_multisynapse::~aeif_cond_alpha_multisynapse() + { + } + + /* ---------------------------------------------------------------- + * Node initialization functions + * ---------------------------------------------------------------- */ + + void aeif_cond_alpha_multisynapse::init_state_(const Node& proto) + { + const aeif_cond_alpha_multisynapse& pr = downcast< + aeif_cond_alpha_multisynapse>(proto); + S_ = pr.S_; + } + + void aeif_cond_alpha_multisynapse::init_buffers_() + { + B_.spike_exc_.clear(); // includes resize + B_.spike_inh_.clear(); // includes resize + B_.currents_.clear(); // includes resize + Archiving_Node::clear_history(); + + B_.logger_.reset(); + + B_.step_ = Time::get_resolution().get_ms(); + + // We must integrate this model with high-precision to obtain decent results + B_.IntegrationStep_ = std::min(0.01, B_.step_); + + B_.I_stim_ = 0.0; + } + + void aeif_cond_alpha_multisynapse::calibrate() + { + B_.logger_.init(); // ensures initialization in case mm connected after Simulate + + P_.receptor_types_.resize(P_.num_of_receptors_); + for (size_t i = 0; i < P_.num_of_receptors_; i++) + { + P_.receptor_types_[i] = i + 1; + } + + V_.g0_ex_.resize(P_.num_of_receptors_); + V_.g0_in_.resize(P_.num_of_receptors_); + + for (size_t i = 0; i < P_.num_of_receptors_; ++i) + { + V_.g0_ex_[i] = 1.0 * numerics::e / P_.taus_syn[i]; + V_.g0_in_[i] = 1.0 * numerics::e / P_.taus_syn[i]; + } + V_.RefractoryCounts_ = Time(Time::ms(P_.t_ref_)).get_steps(); + assert(V_.RefractoryCounts_ >= 0); // since t_ref_ >= 0, this can only fail in error + + B_.spike_exc_.resize(P_.num_of_receptors_); + B_.spike_inh_.resize(P_.num_of_receptors_); + S_.y_.resize( + State_::NUMBER_OF_FIXED_STATES_ELEMENTS + + (State_::NUMBER_OF_STATES_ELEMENTS_PER_RECEPTOR + * P_.num_of_receptors_)); + S_.k1.resize( + State_::NUMBER_OF_FIXED_STATES_ELEMENTS + + (State_::NUMBER_OF_STATES_ELEMENTS_PER_RECEPTOR + * P_.num_of_receptors_)); + S_.k2.resize( + State_::NUMBER_OF_FIXED_STATES_ELEMENTS + + (State_::NUMBER_OF_STATES_ELEMENTS_PER_RECEPTOR + * P_.num_of_receptors_)); + S_.k3.resize( + State_::NUMBER_OF_FIXED_STATES_ELEMENTS + + (State_::NUMBER_OF_STATES_ELEMENTS_PER_RECEPTOR + * P_.num_of_receptors_)); + S_.k4.resize( + State_::NUMBER_OF_FIXED_STATES_ELEMENTS + + (State_::NUMBER_OF_STATES_ELEMENTS_PER_RECEPTOR + * P_.num_of_receptors_)); + S_.k5.resize( + State_::NUMBER_OF_FIXED_STATES_ELEMENTS + + (State_::NUMBER_OF_STATES_ELEMENTS_PER_RECEPTOR + * P_.num_of_receptors_)); + S_.k6.resize( + State_::NUMBER_OF_FIXED_STATES_ELEMENTS + + (State_::NUMBER_OF_STATES_ELEMENTS_PER_RECEPTOR + * P_.num_of_receptors_)); + S_.k7.resize( + State_::NUMBER_OF_FIXED_STATES_ELEMENTS + + (State_::NUMBER_OF_STATES_ELEMENTS_PER_RECEPTOR + * P_.num_of_receptors_)); + S_.yin.resize( + State_::NUMBER_OF_FIXED_STATES_ELEMENTS + + (State_::NUMBER_OF_STATES_ELEMENTS_PER_RECEPTOR + * P_.num_of_receptors_)); + S_.ynew.resize( + State_::NUMBER_OF_FIXED_STATES_ELEMENTS + + (State_::NUMBER_OF_STATES_ELEMENTS_PER_RECEPTOR + * P_.num_of_receptors_)); + S_.yref.resize( + State_::NUMBER_OF_FIXED_STATES_ELEMENTS + + (State_::NUMBER_OF_STATES_ELEMENTS_PER_RECEPTOR + * P_.num_of_receptors_)); + } + + void aeif_cond_alpha_multisynapse::update(Time const& origin, + const long_t from, const long_t to) + { + assert(to >= 0 && (delay ) from < Scheduler::get_min_delay()); + assert(from < to); + assert(State_::V_M == 0); + + for (long_t lag = from; lag < to; ++lag) // proceed by stepsize B_.step_ + { + double t = 0.0; // internal time of the integration period + + if (S_.r_ > 0) // decrease remaining refractory steps if non-zero + --S_.r_; + + // numerical integration with adaptive step size control: + // ------------------------------------------------------ + //The numerical integration of the model equations is performed by + // a Dormand-Prince method (5th order Runge-Kutta method with + // adaptive stepsize control) as desribed in William H. Press et + // al., “Adaptive Stepsize Control for Runge-Kuttaâ€, Chapter 17.2 + // in Numerical Recipes (3rd edition, 2007), 910-914. The solver + // itself performs only a single NUMERICAL integration step, + // starting from t and of size B_.IntegrationStep_ (bounded by + // step); the while-loop ensures integration over the whole + // SIMULATION step (0, step] of size B_.step_ if more than one + // integration step is needed due to a small integration stepsize; + // note that (t+IntegrationStep > step) leads to integration over + // (t, step] and afterwards setting t to step, but it does not + // enforce setting IntegrationStep to step-t; this is of advantage + // for a consistent and efficient integration across subsequent + // simulation intervals. + + double_t &h = B_.IntegrationStep_; // numerical integration step + double_t &tend = B_.step_; // end of simulation step + + const double_t &MAXERR = P_.MAXERR; // maximum error + const double_t &HMIN = P_.HMIN; // minimal integration step + + double_t err; + double_t t_return = 0.0; + + while (t < B_.step_) // while not yet reached end of simulation step + { + bool done = false; + + do + { + + if (tend - t < h) // stop integration at end of simulation step + h = tend - t; + + t_return = t + h; //update t + + // k1 = f(told, y) + aeif_cond_alpha_multisynapse_dynamics(S_.y_, S_.k1); + + // k2 = f(told + h/5, y + h*k1 / 5) + for (size_t i = 0; i < S_.y_.size(); ++i) + S_.yin[i] = S_.y_[i] + h * S_.k1[i] / 5.0; + aeif_cond_alpha_multisynapse_dynamics(S_.yin, S_.k2); + + // k3 = f(told + 3/10*h, y + 3/40*h*k1 + 9/40*h*k2) + for (size_t i = 0; i < S_.y_.size(); ++i) + S_.yin[i] = S_.y_[i] + + h * (3.0 / 40.0 * S_.k1[i] + 9.0 / 40.0 * S_.k2[i]); + aeif_cond_alpha_multisynapse_dynamics(S_.yin, S_.k3); + + // k4 + for (size_t i = 0; i < S_.y_.size(); ++i) + S_.yin[i] = S_.y_[i] + + h + * (44.0 / 45.0 * S_.k1[i] - 56.0 / 15.0 * S_.k2[i] + + 32.0 / 9.0 * S_.k3[i]); + aeif_cond_alpha_multisynapse_dynamics(S_.yin, S_.k4); + + // k5 + for (size_t i = 0; i < S_.y_.size(); ++i) + S_.yin[i] = + S_.y_[i] + + h + * (19372.0 / 6561.0 * S_.k1[i] + - 25360.0 / 2187.0 * S_.k2[i] + + 64448.0 / 6561.0 * S_.k3[i] + - 212.0 / 729.0 * S_.k4[i]); + aeif_cond_alpha_multisynapse_dynamics(S_.yin, S_.k5); + + // k6 + for (size_t i = 0; i < S_.y_.size(); ++i) + S_.yin[i] = S_.y_[i] + + h + * (9017.0 / 3168.0 * S_.k1[i] - 355.0 / 33.0 * S_.k2[i] + + 46732.0 / 5247.0 * S_.k3[i] + 49.0 / 176.0 * S_.k4[i] + - 5103.0 / 18656.0 * S_.k5[i]); + aeif_cond_alpha_multisynapse_dynamics(S_.yin, S_.k6); + + // 5th order + for (size_t i = 0; i < S_.y_.size(); ++i) + S_.ynew[i] = S_.y_[i] + + h + * (35.0 / 384.0 * S_.k1[i] + 500.0 / 1113.0 * S_.k3[i] + + 125.0 / 192.0 * S_.k4[i] - 2187.0 / 6784.0 * S_.k5[i] + + 11.0 / 84.0 * S_.k6[i]); + aeif_cond_alpha_multisynapse_dynamics(S_.yin, S_.k7); + + // 4th order + for (size_t i = 0; i < S_.y_.size(); ++i) + { + S_.yref[i] = S_.y_[i] + + h + * (5179.0 / 57600.0 * S_.k1[i] + 7571.0 / 16695.0 * S_.k3[i] + + 393.0 / 640.0 * S_.k4[i] + - 92097.0 / 339200.0 * S_.k5[i] + + 187.0 / 2100.0 * S_.k6[i] + 1.0 / 40.0 * S_.k7[i]); + } + + err = std::fabs(S_.ynew[0] - S_.yref[0]) / MAXERR + 1.0e-200; //error estimate, + //based on different orders for stepsize prediction. Small value added to prevent err==0 + + // The following flag 'done' is needed to ensure that we accept the result + // for h<=HMIN, irrespective of the error. (See below) + + done = (h <= HMIN); // Always exit loop if h was <=HMIN already + + // prediction of next integration stepsize. This step may result in a stepsize below HMIN. + // If this happens, we must + // 1. set the stepsize to HMIN + // 2. compute the result and accept it irrespective of the error, because we cannot + // decrease the stepsize any further. + // the 'done' flag, computed above ensure that the loop is terminated after the + // result was computed. + + h *= 0.98 * std::pow(1.0 / err, 1.0 / 5.0); + h = std::max(h, HMIN); + + } while ((err > 1.0) and (not done)); //reject step if err > 1 + + for (size_t i = 0; i < S_.y_.size(); ++i) + S_.y_[i] = S_.ynew[i]; // pass updated values + + t = t_return; + + // check for unreasonable values; we allow V_M to explode + if (S_.y_[State_::V_M] < -1e3 || S_.y_[State_::W] < -1e6 + || S_.y_[State_::W] > 1e6) + throw NumericalInstability(get_name()); + + // spikes are handled inside the while-loop + // due to spike-driven adaptation + if (S_.r_ > 0) // if neuron is still in refractory period + S_.y_[State_::V_M] = P_.V_reset_; // clamp it to V_reset + else if (S_.y_[State_::V_M] >= P_.V_peak_) // V_m >= V_peak: spike + { + S_.y_[State_::V_M] = P_.V_reset_; + S_.y_[State_::W] += P_.b; // spike-driven adaptation + S_.r_ = V_.RefractoryCounts_; // initialize refractory steps with refractory period + + set_spiketime(Time::step(origin.get_steps() + lag + 1)); + SpikeEvent se; + network()->send(*this, se, lag); + } + } //while + + for (size_t i = 0; i < P_.num_of_receptors_; ++i) + { + S_.y_[State_::DG_EXC + + (State_::NUMBER_OF_STATES_ELEMENTS_PER_RECEPTOR * i)] += + B_.spike_exc_[i].get_value(lag) * V_.g0_ex_[i]; // add incoming spikes + S_.y_[State_::DG_INH + + (State_::NUMBER_OF_STATES_ELEMENTS_PER_RECEPTOR * i)] += + B_.spike_inh_[i].get_value(lag) * V_.g0_in_[i]; + } + // set new input current + B_.I_stim_ = B_.currents_.get_value(lag); + + // log state data + B_.logger_.record_data(origin.get_steps() + lag); + + } // for-loop + } + + port aeif_cond_alpha_multisynapse::connect_sender(SpikeEvent&, + port receptor_type) + { + if (receptor_type <= 0 + || receptor_type > static_cast(P_.num_of_receptors_)) + throw IncompatibleReceptorType(receptor_type, get_name(), "SpikeEvent"); + + P_.has_connections_ = true; + return receptor_type; + } + + void aeif_cond_alpha_multisynapse::handle(SpikeEvent& e) + { + assert(e.get_delay() > 0); + assert((e.get_rport() > 0) && ((size_t)e.get_rport() <= P_.num_of_receptors_)); + + if (e.get_weight() > 0.0) + { + B_.spike_exc_[e.get_rport() - 1].add_value( + e.get_rel_delivery_steps(network()->get_slice_origin()), + e.get_weight() * e.get_multiplicity()); + } + else + { + B_.spike_inh_[e.get_rport() - 1].add_value( + e.get_rel_delivery_steps(network()->get_slice_origin()), + -e.get_weight() * e.get_multiplicity()); // keep conductances positive + } + } + + void aeif_cond_alpha_multisynapse::handle(CurrentEvent& e) + { + assert(e.get_delay() > 0); + + const double_t I = e.get_current(); + const double_t w = e.get_weight(); + + // add weighted current; HEP 2002-10-04 + B_.currents_.add_value( + e.get_rel_delivery_steps(network()->get_slice_origin()), w * I); + } + + void aeif_cond_alpha_multisynapse::handle(DataLoggingRequest& e) + { + B_.logger_.handle(e); + } + +} // namespace diff --git a/models/aeif_cond_alpha_multisynapse.h b/models/aeif_cond_alpha_multisynapse.h new file mode 100644 index 0000000000..51c8fc2d54 --- /dev/null +++ b/models/aeif_cond_alpha_multisynapse.h @@ -0,0 +1,428 @@ +/* + * aeif_cond_alpha_multisynapse.h + * + * This file is part of NEST. + * + * Copyright (C) 2004 The NEST Initiative + * + * NEST 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 2 of the License, or + * (at your option) any later version. + * + * NEST 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 NEST. If not, see . + * + */ + +#ifndef AEIF_COND_ALPHA_MULTISYNAPSE_H +#define AEIF_COND_ALPHA_MULTISYNAPSE_H + +#include "nest.h" +#include "event.h" +#include "archiving_node.h" +#include "ring_buffer.h" +#include "connection.h" +#include "universal_data_logger.h" +#include "recordables_map.h" + +/* BeginDocumentation + Name: aeif_cond_alpha_multisynapse - Conductance based exponential integrate-and-fire neuron model according to Brette and Gerstner (2005) with multiple synaptic time constants. + + Description: + + aeif_cond_alpha_multisynapse is a direct extension of + aeif_cond_alpha_RK5. In contrast to most other neuron models, this + one allow an arbitrary number of synaptic time constant. + + The time constants are supplied by two arrays tau_ex and tau_in for + the excitatory and inhibitory synapses, respectively. Port numbers + are then automatically assigned and there range is from 1 to n. (n + being the index of the last element of the tau_ex and tau_in + arrays). + During connection, the ports are selected with the property "receptor_type". + + Examples: + % PyNEST example, of how to assign a synaptic time constant to a receptor type. + + nest.SetDefaults('aeif_cond_alpha_multisynapse', {'HMIN':0.001}) + nest.SetDefaults('aeif_cond_alpha_multisynapse', {'MAXERR':1e-10}) + + neuron = nest.Create('aeif_cond_alpha_multisynapse') + nest.SetStatus(neuron, {"V_peak": 0.0, "a": 4.0, "b":80.5}) + nest.SetStatus(neuron, {'taus_syn':[0.2,2.0,20.0,20.0]}) + + spike = nest.Create('spike_generator', params = {'spike_times': np.array([100.0])}) + voltmeter = nest.Create('voltmeter', 1, {'withgid': True}) + + nest.CopyModel("static_synapse", "synapse1", {"weight":1.0, "delay":1.0, 'receptor_type': 1}) + nest.CopyModel("static_synapse", "synapse2", {"weight":1.0, "delay":100.0, 'receptor_type': 2}) + nest.CopyModel("static_synapse", "synapse3", {"weight":1.0, "delay":300.0, 'receptor_type': 3}) + nest.CopyModel("static_synapse", "synapse4", {"weight":-1.0, "delay":500.0, 'receptor_type': 4}) + + nest.Connect(spike, neuron, model="synapse1") + nest.Connect(spike, neuron, model="synapse2") + nest.Connect(spike, neuron, model="synapse3") + nest.Connect(spike, neuron, model="synapse4") + + nest.Connect(voltmeter, neuron) + + Sends: SpikeEvent + + Receives: SpikeEvent, CurrentEvent, DataLoggingRequest + + Author: Daniel Peppicelli, adapted from aeif_cond_alpha_RK5 + SeeAlso: aeif_cond_alpha_RK5 + */ + +namespace nest +{ + class Network; + + /** + * Conductance based exponential integrate-and-fire neuron model according to Brette and Gerstner (2005) with multiple ports. + */ + class aeif_cond_alpha_multisynapse: public Archiving_Node + { + + public: + + aeif_cond_alpha_multisynapse(); + aeif_cond_alpha_multisynapse(const aeif_cond_alpha_multisynapse&); + virtual + ~aeif_cond_alpha_multisynapse(); + + /** + * Import sets of overloaded virtual functions. + * @see Technical Issues / Virtual Functions: Overriding, Overloading, and Hiding + */ + + using Node::connect_sender; + using Node::handle; + + port check_connection(Connection&, port); + + void handle(SpikeEvent &); + void handle(CurrentEvent &); + void handle(DataLoggingRequest &); + + port connect_sender(SpikeEvent&, port); + port connect_sender(CurrentEvent&, port); + port connect_sender(DataLoggingRequest&, port); + + void get_status(DictionaryDatum &) const; + void set_status(const DictionaryDatum &); + + private: + + void init_state_(const Node& proto); + void init_buffers_(); + void calibrate(); + void update(Time const&, const long_t, const long_t); + + inline void aeif_cond_alpha_multisynapse_dynamics( + const std::vector& y, std::vector& f); + + // The next two classes need to be friends to access the State_ class/member + friend class RecordablesMap ; + friend class UniversalDataLogger ; + + // ---------------------------------------------------------------- + + /** + * Independent parameters of the model. + */ + struct Parameters_ + { + double_t V_peak_; //!< Spike detection threshold in mV + double_t V_reset_; //!< Reset Potential in mV + double_t t_ref_; //!< Refractory period in ms + + double_t g_L; //!< Leak Conductance in nS + double_t C_m; //!< Membrane Capacitance in pF + double_t E_ex; //!< Excitatory reversal Potential in mV + double_t E_in; //!< Inhibitory reversal Potential in mV + double_t E_L; //!< Leak reversal Potential (aka resting potential) in mV + double_t Delta_T; //!< Slope faktor in ms. + double_t tau_w; //!< adaptation time-constant in ms. + double_t a; //!< Subthreshold adaptation in nS. + double_t b; //!< Spike-triggered adaptation in pA + double_t V_th; //!< Spike threshold in mV. + double_t t_ref; //!< Refractory period in ms. + std::vector taus_syn; //!< Time constants of synaptic currents in ms.. + double_t I_e; //!< Intrinsic current in pA. + double_t MAXERR; //!< Maximal error for adaptive stepsize solver + double_t HMIN; //!< Smallest permissible stepsize in ms. + + // type is long because other types are not put through in GetStatus + std::vector receptor_types_; + size_t num_of_receptors_; + + // boolean flag which indicates whether the neuron has connections + bool has_connections_; + + Parameters_(); //!< Sets default parameter values + + void get(DictionaryDatum&) const; //!< Store current values in dictionary + void set(const DictionaryDatum&); //!< Set values from dictionary + + }; + + // ---------------------------------------------------------------- + + /** + * State variables of the model. + * @note Copy constructor and assignment operator required because + * of C-style arrays. + */ + struct State_ + { + + /** + * Enumeration identifying elements in state vector State_::y_. + * This enum identifies the elements of the vector. It must be public to be + * accessible from the iteration function. The last four elements of this + * enum (DG_EXC, G_EXC, DG_INH, G_INH) will be repeated n times at the end + * of the state vector State_::y with n being the number of synapses. + */ + enum StateVecElems + { + V_M = 0, W, // 1 + DG_EXC, // 2 + G_EXC, // 3 + DG_INH, // 4 + G_INH, // 5 + STATE_VECTOR_MIN_SIZE + }; + + static const size_t NUMBER_OF_FIXED_STATES_ELEMENTS = 2; // V_M, W + static const size_t NUMBER_OF_STATES_ELEMENTS_PER_RECEPTOR = 4; // DG_EXC, G_EXC, DG_INH, G_INH + + std::vector y_; //!< neuron state + std::vector k1; //!< Runge-Kutta variable + std::vector k2; //!< Runge-Kutta variable + std::vector k3; //!< Runge-Kutta variable + std::vector k4; //!< Runge-Kutta variable + std::vector k5; //!< Runge-Kutta variable + std::vector k6; //!< Runge-Kutta variable + std::vector k7; //!< Runge-Kutta variable + std::vector yin; //!< Runge-Kutta variable + std::vector ynew; //!< 5th order update + std::vector yref; //!< 4th order update + int_t r_; //!< number of refractory steps remaining + + State_(const Parameters_&); //!< Default initialization + State_(const State_&); + State_& operator=(const State_&); + + void get(DictionaryDatum&) const; + void set(const DictionaryDatum&); + + }; // State_ + + // ---------------------------------------------------------------- + + /** + * Buffers of the model. + */ + struct Buffers_ + { + Buffers_(aeif_cond_alpha_multisynapse &); + Buffers_(const Buffers_ &, aeif_cond_alpha_multisynapse &); + + //! Logger for all analog data + UniversalDataLogger logger_; + + /** buffers and sums up incoming spikes/currents */ + std::vector spike_exc_; + std::vector spike_inh_; + RingBuffer currents_; + + // IntergrationStep_ should be reset with the neuron on ResetNetwork, + // but remain unchanged during calibration. Since it is initialized with + // step_, and the resolution cannot change after nodes have been created, + // it is safe to place both here. + double_t step_; //!< simulation step size in ms + double IntegrationStep_; //!< current integration time step, updated by solver + + /** + * Input current injected by CurrentEvent. + * This variable is used to transport the current applied into the + * _dynamics function computing the derivative of the state vector. + * It must be a part of Buffers_, since it is initialized once before + * the first simulation, but not modified before later Simulate calls. + */ + double_t I_stim_; + }; + + // ---------------------------------------------------------------- + + /** + * Internal variables of the model. + */ + struct Variables_ + { + + /** initial value to normalise excitatory synaptic conductance */ + std::vector g0_ex_; + + /** initial value to normalise inhibitory synaptic conductance */ + std::vector g0_in_; + + int_t RefractoryCounts_; + }; + + // Access functions for UniversalDataLogger ------------------------------- + + //! Read out state vector elements, used by UniversalDataLogger + template double_t get_y_elem_() const + { + return S_.y_[elem]; + } + + // Data members ----------------------------------------------------------- + + /** + * @defgroup aeif_cond_alpha_multisynapse + * Instances of private data structures for the different types + * of data pertaining to the model. + * @note The order of definitions is important for speed. + * @{ + */ + Parameters_ P_; + State_ S_; + Variables_ V_; + Buffers_ B_; + /** @} */ + + //! Mapping of recordables names to access functions + static RecordablesMap recordablesMap_; + + }; + + inline + port aeif_cond_alpha_multisynapse::check_connection(Connection& c, + port receptor_type) + { + SpikeEvent e; + e.set_sender(*this); + c.check_event(e); + return c.get_target()->connect_sender(e, receptor_type); + } + + inline + port aeif_cond_alpha_multisynapse::connect_sender(CurrentEvent&, + port receptor_type) + { + if (receptor_type != 0) + throw UnknownReceptorType(receptor_type, get_name()); + return 0; + } + + inline + port aeif_cond_alpha_multisynapse::connect_sender( + DataLoggingRequest& dlr, port receptor_type) + { + if (receptor_type != 0) + throw UnknownReceptorType(receptor_type, get_name()); + return B_.logger_.connect_logging_device(dlr, recordablesMap_); + } + + inline + void aeif_cond_alpha_multisynapse::get_status(DictionaryDatum &d) const + { + P_.get(d); + S_.get(d); + Archiving_Node::get_status(d); + + (*d)[names::recordables] = recordablesMap_.get_list(); + } + + inline + void aeif_cond_alpha_multisynapse::set_status(const DictionaryDatum &d) + { + Parameters_ ptmp = P_; // temporary copy in case of errors + ptmp.set(d); // throws if BadProperty + State_ stmp = S_; // temporary copy in case of errors + stmp.set(d); // throws if BadProperty + + // We now know that (ptmp, stmp) are consistent. We do not + // write them back to (P_, S_) before we are also sure that + // the properties to be set in the parent class are internally + // consistent. + Archiving_Node::set_status(d); + + // if we get here, temporaries contain consistent set of properties + P_ = ptmp; + S_ = stmp; + } + + /** + * Function computing right-hand side of ODE for the ODE solver. + * @param y State vector (input). + * @param f Derivatives (output). + */ + inline + void aeif_cond_alpha_multisynapse::aeif_cond_alpha_multisynapse_dynamics( + const std::vector& y, std::vector& f) + { + // a shorthand + typedef aeif_cond_alpha_multisynapse::State_ S; + + // y[] is the current internal state of the integrator (yin), not the state vector in the node, node.S_.y[]. + + // The following code is verbose for the sake of clarity. We assume that a + // good compiler will optimize the verbosity away ... + + // This constant is used below as the largest admissible value for the exponential spike upstroke + static const double_t largest_exp = std::exp(10.); + + // shorthand for state variables + const double_t& V = y[S::V_M]; + const double_t& w = y[S::W]; + + double_t I_syn_exc = 0.0; + double_t I_syn_inh = 0.0; + + for (size_t i = 0; + i < (P_.num_of_receptors_ * S::NUMBER_OF_STATES_ELEMENTS_PER_RECEPTOR); + i += S::NUMBER_OF_STATES_ELEMENTS_PER_RECEPTOR) + { + I_syn_exc += y[S::G_EXC + i] * (V - P_.E_ex); + I_syn_inh += y[S::G_INH + i] * (V - P_.E_in); + } + + // We pre-compute the argument of the exponential + const double_t exp_arg = (V - P_.V_th) / P_.Delta_T; + // If the argument is too large, we clip it. + const double_t I_spike = + (exp_arg > 10.) ? largest_exp : P_.Delta_T * std::exp(exp_arg); + + // dv/dt + f[S::V_M] = (-P_.g_L * ((V - P_.E_L) - I_spike) - I_syn_exc - I_syn_inh - w + + P_.I_e + B_.I_stim_) / P_.C_m; + + // Adaptation current w. + f[S::W] = (P_.a * (V - P_.E_L) - w) / P_.tau_w; + + size_t j = 0; + for (size_t i = 0; i < P_.num_of_receptors_; ++i) + { + j = i * S::NUMBER_OF_STATES_ELEMENTS_PER_RECEPTOR; + f[S::DG_EXC + j] = -y[S::DG_EXC + j] / P_.taus_syn[i]; + f[S::G_EXC + j] = y[S::DG_EXC + j] - y[S::G_EXC + j] / P_.taus_syn[i]; // Synaptic Conductance (nS) + + f[S::DG_INH + j] = -y[S::DG_INH + j] / P_.taus_syn[i]; + f[S::G_INH + j] = y[S::DG_INH + j] - y[S::G_INH + j] / P_.taus_syn[i]; // Synaptic Conductance (nS) + } + + } + +} // namespace + +#endif /* #ifndef AEIF_COND_ALPHA_MULTISYNAPSE_H */ diff --git a/models/binary_neuron.h b/models/binary_neuron.h index a7c21ec4e5..b609a3bd6d 100644 --- a/models/binary_neuron.h +++ b/models/binary_neuron.h @@ -46,18 +46,12 @@ namespace nest{ public: - typedef Node base; - binary_neuron(); binary_neuron(const binary_neuron&); /** * Import sets of overloaded virtual functions. - * We need to explicitly include sets of overloaded - * virtual functions into the current scope. - * According to the SUN C++ FAQ, this is the correct - * way of doing things, although all other compilers - * happily live without. + * @see Technical Issues / Virtual Functions: Overriding, Overloading, and Hiding */ using Node::connect_sender; @@ -86,8 +80,6 @@ namespace nest{ // must have an double_t operator(double_t) defined TGainfunction gain_; - //double_t gain_(double_t h); - void update(Time const &, const long_t, const long_t); // The next two classes need to be friends to access the State_ class/member diff --git a/models/binary_neuron_impl.h b/models/binary_neuron_impl.h index 93094f0971..0d08f20449 100644 --- a/models/binary_neuron_impl.h +++ b/models/binary_neuron_impl.h @@ -1,5 +1,5 @@ /* - * binary_neuron_impl.cpp + * binary_neuron_impl.h * * This file is part of NEST. * @@ -175,6 +175,8 @@ void binary_neuron::update(Time const & origin, // of the total input h with respect to the previous step, so sum them up S_.h_ += B_.spikes_.get_value(lag); + double_t c = B_.currents_.get_value(lag); + // check, if the update needs to be done if ( Time::step(origin.get_steps()+lag) > S_.t_next_ ) { @@ -182,7 +184,7 @@ void binary_neuron::update(Time const & origin, // gain function // if the state has changed, the neuron produces an event sent to all its targets - bool new_y = gain_(V_.rng_, S_.h_ + B_.currents_.get_value(lag) ); + bool new_y = gain_(V_.rng_, S_.h_ + c); if ( new_y != S_.y_ ) { @@ -237,7 +239,7 @@ void binary_neuron::handle(SpikeEvent & e) // count this event negatively, assuming it comes as single event // transition 1->0 B_.spikes_.add_value(e.get_rel_delivery_steps(network()->get_slice_origin()), - -e.get_weight()); + -e.get_weight()); } } else // multiplicity != 1 @@ -264,7 +266,8 @@ void binary_neuron::handle(CurrentEvent& e) // but also to handle the incoming current events added // both contributions are directly added to the variable h B_.currents_.add_value(e.get_rel_delivery_steps(network()->get_slice_origin()), - w *c); + w*c); + } diff --git a/models/cont_delay_connection.cpp b/models/cont_delay_connection.cpp index f1b42b73f5..a6f3b54a34 100644 --- a/models/cont_delay_connection.cpp +++ b/models/cont_delay_connection.cpp @@ -1,4 +1,3 @@ - /* * cont_delay_connection.cpp * @@ -20,6 +19,7 @@ * along with NEST. If not, see . * */ + #include "network.h" #include "dictdatum.h" #include "connector_model.h" @@ -55,7 +55,7 @@ namespace nest } } - + void ContDelayConnection::set_status(const DictionaryDatum & d, ConnectorModel &cm) { //set delay if mentioned @@ -63,10 +63,11 @@ namespace nest if (updateValue(d, names::delay, delay)) { - double int_delay; - long_t lowerbound; double_t h = Time::get_resolution().get_ms(); + + double_t int_delay; double_t frac_delay = std::modf(delay/h, &int_delay); + if (frac_delay == 0) { if (!cm.check_delay(delay)) @@ -76,7 +77,7 @@ namespace nest } else { - lowerbound = (long_t)(int_delay); + long_t lowerbound = static_cast(int_delay); if (!cm.check_delays(Time(Time::step(lowerbound)).get_ms(), Time(Time::step(lowerbound + 1)).get_ms())) throw BadDelay(lowerbound); @@ -90,7 +91,7 @@ namespace nest /** * Set properties of this connection from position p in the properties * array given in dictionary. - */ + */ void ContDelayConnection::set_status(const DictionaryDatum & d, index p, ConnectorModel &cm) { @@ -98,10 +99,12 @@ namespace nest double_t delay; if ( set_property(d, names::delays, p, delay) ) { - double int_delay; - long_t lowerbound; + double_t h = Time::get_resolution().get_ms(); + + double_t int_delay; double_t frac_delay = std::modf(delay/h, &int_delay); + if (frac_delay == 0) { if (!cm.check_delay(delay)) @@ -111,7 +114,7 @@ namespace nest } else { - lowerbound = (long_t)(int_delay); + long_t lowerbound = static_cast(int_delay); if (!cm.check_delays(Time(Time::step(lowerbound)).get_ms(), Time(Time::step(lowerbound + 1)).get_ms())) throw BadDelay(lowerbound); @@ -121,7 +124,7 @@ namespace nest } set_property(d, names::weights, p, weight_); } - + /** * Append properties of this connection to the given dictionary. If the * dictionary is empty, new arrays are created first. diff --git a/models/correlomatrix_detector.cpp b/models/correlomatrix_detector.cpp new file mode 100644 index 0000000000..9db359cebc --- /dev/null +++ b/models/correlomatrix_detector.cpp @@ -0,0 +1,342 @@ +/* + * correlomatrix_detector.cpp + * + * This file is part of NEST. + * + * Copyright (C) 2004 The NEST Initiative + * + * NEST 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 2 of the License, or + * (at your option) any later version. + * + * NEST 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 NEST. If not, see . + * + */ + +#include "correlomatrix_detector.h" +#include "network.h" +#include "dict.h" +#include "dictutils.h" +#include "arraydatum.h" + +#include +#include // for bind2nd +#include // for less + +/* ---------------------------------------------------------------- + * Default constructors defining default parameters and state + * ---------------------------------------------------------------- */ + +nest::correlomatrix_detector::Parameters_::Parameters_() + : delta_tau_(Time::ms(0.5)), + tau_max_ (10 * delta_tau_), + Tstart_ (Time::ms(0.0)), + Tstop_ (Time::pos_inf()), + N_channels_ (1) +{} + +nest::correlomatrix_detector::Parameters_::Parameters_(const Parameters_& p) + : delta_tau_(p.delta_tau_), + tau_max_ (p.tau_max_), + Tstart_ (p.Tstart_), + Tstop_ (p.Tstop_), + N_channels_ (p.N_channels_) +{ + // Check for proper properties is not done here but in the + // correlomatrix_detector() copy c'tor. The check cannot be + // placed here, since this c'tor is also used to copy to + // temporaries in correlomatrix_detector::set_status(). + // If we checked for errors here, we could never change values + // that have become invalid after a resolution change. + delta_tau_.calibrate(); + tau_max_.calibrate(); + Tstart_.calibrate(); + Tstop_.calibrate(); +} + +nest::correlomatrix_detector::State_::State_() + : n_events_(1, 0), + incoming_(), + covariance_ (1,std::vector >(1,std::vector())), + count_covariance_ (1,std::vector >(1,std::vector())) +{} + + +/* ---------------------------------------------------------------- + * Parameter extraction and manipulation functions + * ---------------------------------------------------------------- */ + +void nest::correlomatrix_detector::Parameters_::get(DictionaryDatum &d) const +{ + (*d)[names::delta_tau] = delta_tau_.get_ms(); + (*d)[names::tau_max] = tau_max_.get_ms(); + (*d)[names::Tstart] = Tstart_.get_ms(); + (*d)[names::Tstop] = Tstop_.get_ms(); + (*d)[names::N_channels] = N_channels_; +} + +void nest::correlomatrix_detector::State_::get(DictionaryDatum &d) const +{ + (*d)[names::n_events] = IntVectorDatum(new std::vector(n_events_)); + + ArrayDatum *C = new ArrayDatum; + ArrayDatum *CountC = new ArrayDatum; + for (size_t i = 0; i < covariance_.size(); ++i) + { + ArrayDatum *C_i = new ArrayDatum; + ArrayDatum *CountC_i = new ArrayDatum; + for(size_t j = 0; j < covariance_[i].size(); ++j) + { + C_i->push_back( new DoubleVectorDatum( new std::vector(covariance_[i][j]) )); + CountC_i->push_back( new IntVectorDatum( new std::vector(count_covariance_[i][j]) )); + } + C->push_back(*C_i); + CountC->push_back(*CountC_i); + } + (*d)[names::covariance] = C; + (*d)[names::count_covariance] = CountC; +} + +bool nest::correlomatrix_detector::Parameters_::set(const DictionaryDatum& d, + const correlomatrix_detector& n) +{ + bool reset = false; + double_t t; + long_t N; + + if (updateValue(d, names::N_channels, N) ) + { + if (N<1) + { + throw BadProperty("/N_channels can only be larger than zero."); + } + else + { + N_channels_ = N; + reset = true; + } + } + + if ( updateValue(d, names::delta_tau, t) ) + { + delta_tau_ = Time::ms(t); + reset = true; + } + + if ( updateValue(d, names::tau_max, t) ) + { + tau_max_ = Time::ms(t); + reset = true; + } + + if ( updateValue(d, names::Tstart, t) ) + { + Tstart_ = Time::ms(t); + reset = true; + } + + if ( updateValue(d, names::Tstop, t) ) + { + Tstop_ = Time::ms(t); + reset = true; + } + + if ( !delta_tau_.is_step() ) + throw StepMultipleRequired(n.get_name(), names::delta_tau, delta_tau_); + + if ( !tau_max_.is_multiple_of(delta_tau_) ) + throw TimeMultipleRequired(n.get_name(), names::tau_max, tau_max_, + names::delta_tau, delta_tau_); + + if ( delta_tau_.get_steps() % 2 != 1 ) + throw BadProperty("/delta_tau must be odd multiple of resolution."); + + return reset; +} + +void nest::correlomatrix_detector::State_::set(const DictionaryDatum&, const Parameters_&, bool) +{} + +void nest::correlomatrix_detector::State_::reset(const Parameters_& p) +{ + n_events_.clear(); + n_events_.resize(p.N_channels_, 0); + + incoming_.clear(); + + assert(p.tau_max_.is_multiple_of(p.delta_tau_)); + + covariance_.clear(); + covariance_.resize(p.N_channels_); + + count_covariance_.clear(); + count_covariance_.resize(p.N_channels_); + + for(long_t i = 0; i < p.N_channels_; ++i) + { + covariance_[i].resize(p.N_channels_); + count_covariance_[i].resize(p.N_channels_); + for(long_t j = 0; j (proto); + + device_.init_state(pr.device_); + S_ = pr.S_; + unset(buffers_initialized); // force recreation of buffers +} + +void nest::correlomatrix_detector::init_buffers_() +{ + device_.init_buffers(); + S_.reset(P_); +} + +void nest::correlomatrix_detector::calibrate() +{ + device_.calibrate(); +} + + +/* ---------------------------------------------------------------- + * Other functions + * ---------------------------------------------------------------- */ + +void nest::correlomatrix_detector::update(Time const &, const long_t, const long_t) +{} + +void nest::correlomatrix_detector::handle(SpikeEvent & e) +{ + // The receiver port identifies the sending node in our + // sender list. + const rport sender = e.get_rport(); + + // If this assertion breaks, the sender does not honor the + // receiver port during connection or sending. + assert(0 <= sender && sender <= P_.N_channels_-1); + + // accept spikes only if detector was active when spike was emitted + Time const stamp = e.get_stamp(); + + if ( device_.is_active(stamp) ) + { + const long_t spike_i = stamp.get_steps(); + + // find first appearence of element which is greater than spike_i + const Spike_ sp_i(spike_i, e.get_multiplicity()*e.get_weight(),sender); + SpikelistType::iterator insert_pos = + std::find_if(S_.incoming_.begin(), S_.incoming_.end(), + std::bind2nd(std::greater(), sp_i)); + + // insert before the position we have found + // if no element greater found, insert_pos == end(), so append at the end of the deque + S_.incoming_.insert(insert_pos, sp_i); + + SpikelistType& otherSpikes = S_.incoming_; + const double_t tau_edge = P_.tau_max_.get_steps() + 0.5*P_.delta_tau_.get_steps(); + + // throw away all spikes which are too old to + // enter the correlation window + const delay min_delay = Scheduler::get_min_delay(); + while ( !otherSpikes.empty() && (spike_i - otherSpikes.front().timestep_) >= tau_edge + min_delay) + otherSpikes.pop_front(); + // all remaining spike times in the queue are >= spike_i - tau_edge - min_delay + + // only count events in histogram, if the current event is within the time window [Tstart, Tstop] + // this is needed in order to prevent boundary effects + if (P_.Tstart_ <= stamp && stamp <= P_.Tstop_) + { + // calculate the effect of this spike immediately with respect to all + // spikes in the past of the respectively other sources + + S_.n_events_[sender]++; // count this spike + + for (SpikelistType::const_iterator spike_j = otherSpikes.begin(); + spike_j != otherSpikes.end(); + ++spike_j) + { + size_t bin; + long_t other = spike_j->receptor_channel_; + long_t sender_ind,other_ind; + + if (spike_i < spike_j->timestep_) + { + sender_ind = other; + other_ind = sender; + } + else + { + sender_ind = sender; + other_ind = other; + } + + if (sender_ind<=other_ind) + { + bin = -1. * std::floor( (0.5*P_.delta_tau_.get_steps() - std::abs(spike_i - spike_j->timestep_)) / P_.delta_tau_.get_steps() ); + } + else + { + bin = std::floor( (0.5*P_.delta_tau_.get_steps() + std::abs(spike_i - spike_j->timestep_)) / P_.delta_tau_.get_steps() ); + } + + if(bin < S_.covariance_[sender_ind][other_ind].size()) + { + // weighted histogram + S_.covariance_[sender_ind][other_ind][bin] += e.get_multiplicity() * e.get_weight() * spike_j->weight_; + if(bin==0 && (spike_i - spike_j->timestep_ != 0 || other != sender)) + S_.covariance_[other_ind][sender_ind][bin] += e.get_multiplicity() * e.get_weight() * spike_j->weight_; + // pure (unweighted) count histogram + S_.count_covariance_[sender_ind][other_ind][bin] += e.get_multiplicity(); + if(bin==0 && (spike_i - spike_j->timestep_ != 0 || other != sender)) + S_.count_covariance_[other_ind][sender_ind][bin] += e.get_multiplicity(); + } + } + + } // t in [TStart, Tstop] + + } // device active +} diff --git a/models/correlomatrix_detector.h b/models/correlomatrix_detector.h new file mode 100644 index 0000000000..3159f96ab2 --- /dev/null +++ b/models/correlomatrix_detector.h @@ -0,0 +1,295 @@ +/* + * correlomatrix_detector.h + * + * This file is part of NEST. + * + * Copyright (C) 2004 The NEST Initiative + * + * NEST 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 2 of the License, or + * (at your option) any later version. + * + * NEST 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 NEST. If not, see . + * + */ + +#ifndef CORRELOMATRIX_DETECTOR_H +#define CORRELOMATRIX_DETECTOR_H + + +#include +#include +#include "nest.h" +#include "event.h" +#include "node.h" +#include "pseudo_recording_device.h" + +/* BeginDocumentation + + Name: correlomatrix_detector - Device for measuring the covariance matrix from several inputs + + Description: The correlomatrix_detector is a recording device. It is used to record spikes from + several pools of spike inputs and calculates the covariance matrix of inter-spike intervals + (raw auto and cross correlation) binned to bins of duration delta_tau. The histogram is only + recorded for non-negative time lags. The negative part can be obtained by the symmetry of the + covariance matrix C(t) = C^T(-t). + The result can be obtained via GetStatus under the key /count_covariance. + In parallel it records a weighted histogram, where the connection weight are used to weight every + count, which is available under the key /covariance. + Both are matrices of size N_channels x N_channels, with each entry C_ij being a vector of + size tau_max/delta_tau + 1 containing the (weighted) histogram for non-negative time lags. + + The bins are centered around the time difference they represent, and are left-closed + and right-open in the lower triangular part of the matrix. On the diagonal and in the upper + triangular part the intervals are left-open and right-closed. This ensures proper counting + of events at the border of bins, allowing consistent integration of a histogram over negative + and positive time lags by stacking two parts of the histogram (C(t)=[C[i][j][::-1],C[j][i][1:]]). + In this case one needs to exclude C[j][i][0] to avoid counting the zero-lag bin twice. + + The correlomatrix_detector has a variable number of inputs which can be set via SetStatus under + the key N_channels. All incoming connections to a specified receptor will be pooled. + + Parameters: + Tstart double - Time when to start counting events. This time should be set to at least + start + tau_max in order to avoid edge effects of the correlation counts. + Tstop double - Time when to stop counting events. This time should be set to at most + Tsim - tau_max, where Tsim is the duration of simulation, + in order to avoid edge effects of the correlation counts. + delta_tau double - bin width in ms. This has to be an odd multiple of the resolution, to allow + the symmetry between positive and negative time-lags. + tau_max double - one-sided width in ms. In the lower triagnular part events with differences in + [0, tau_max+delta_tau/2) are counted. On the diagonal and in + the upper triangular part events with differences in (0, tau_max+delta_tau/2] + + N_channels long - The number of pools. This defines the range of receptor_type. Default is 1. + Setting N_channels clears count_covariance, covariance and n_events. + + covariance matrix of double vectors, read-only - raw, weighted auto/cross correlation counts + count_covariance matrix of long vectors, read-only - raw, auto/cross correlation counts + n_events integer vector - number of events from all sources. + + Remarks: This recorder does not record to file, screen or memory in the usual sense. + + Example: + /s1 /spike_generator Create def + /s2 /spike_generator Create def + s1 << /spike_times [ 1.0 1.5 2.7 4.0 5.1 ] >> SetStatus + s2 << /spike_times [ 0.9 1.8 2.1 2.3 3.5 3.8 4.9 ] >> SetStatus + /cm /correlomatrix_detector Create def + cm << /N_channels 2 /delta_tau 0.5 /tau_max 2.5 >> SetStatus + s1 cm << /receptor_type 0 >> Connect + s2 cm << /receptor_type 1 >> Connect + 10 Simulate + cm [/n_events] get == --> [# 5 7 #] + cm [/count_covariance] get == --> [[<# 5 1 2 2 0 2 #> <# 3 4 1 3 3 0 #>] [<# 3 2 6 1 2 2 #> <# 9 3 4 6 1 2 #>]] + cm << /N_channels 2 >> SetStatus + cm [/count_covariance] get == --> [[<# 0 0 0 0 0 0 #> <# 0 0 0 0 0 0 #>] [<# 0 0 0 0 0 0 #> <# 0 0 0 0 0 0 #>]] + + Receives: SpikeEvent + + Author: Dmytro Grytskyy + Jakob Jordan + FirstVersion: 2013/02/27 + SeeAlso: correlation_detector, spike_detector, Device, PseudoRecordingDevice + Availability: NEST +*/ + + +namespace nest +{ + + class Network; + + /** + * Correlomatrixdetector class. + * + * @note Correlomatrix detectors IGNORE any connection delays. + * + * @note Correlomatrix detector breaks with the persistence scheme as + * follows: the internal buffers for storing spikes are part + * of State_, but are initialized by init_buffers_(). + * + * @todo The correlation detector could be made more efficient as follows + * (HEP 2008-07-01): + * - incoming_ is vector of two deques + * - let handle() push_back() entries in incoming_ and do nothing else + * - keep index to last "old spike" in each incoming_; cannot + * be iterator since that may change + * - update() deletes all entries before now-tau_max, sorts the new entries, + * then registers new entries in histogram + */ + + class correlomatrix_detector : public Node + { + + public: + + correlomatrix_detector(); + correlomatrix_detector(const correlomatrix_detector &); + + /** + * This device has proxies, so that it will receive + * spikes also from sources which live on other threads. + */ + bool has_proxies() const {return true;} + + /** + * Import sets of overloaded virtual functions. + * We need to explicitly include sets of overloaded + * virtual functions into the current scope. + * According to the SUN C++ FAQ, this is the correct + * way of doing things, although all other compilers + * happily live without. + */ + using Node::connect_sender; + using Node::handle; + + void handle(SpikeEvent &); + port connect_sender(SpikeEvent &, port); + + void get_status(DictionaryDatum &) const; + void set_status(const DictionaryDatum &); + + private: + + void init_state_(Node const&); + void init_buffers_(); + void calibrate(); + + void update(Time const &, const long_t, const long_t); + + // ------------------------------------------------------------ + + /** + * Spike structure to store in the deque of recently + * received events + */ + struct Spike_ + { + long_t timestep_; + double_t weight_; + long_t receptor_channel_; + + Spike_(long_t timestep, double_t weight, long_t receptorchannel) + : timestep_(timestep), weight_(weight), receptor_channel_(receptorchannel) + {} + + /** + * Greater operator needed for insertion sort. + */ + inline bool operator>(const Spike_ &second) const + { + return timestep_ > second.timestep_; + } + }; + + typedef std::deque SpikelistType; + + // ------------------------------------------------------------ + + struct State_; + + struct Parameters_ { + + Time delta_tau_; //!< width of correlation histogram bins + Time tau_max_; //!< maximum time difference of events to detect + Time Tstart_; //!< start of recording + Time Tstop_; //!< end of recording + long_t N_channels_; //!< number of channels + + Parameters_(); //!< Sets default parameter values + Parameters_(const Parameters_&); //!< Recalibrate all times + + void get(DictionaryDatum&) const; //!< Store current values in dictionary + + /** + * Set values from dicitonary. + * @returns true if the state needs to be reset after a change of + * binwidth or tau_max. + */ + bool set(const DictionaryDatum&, const correlomatrix_detector&); + }; + + // ------------------------------------------------------------ + + /** + * @todo Is there a replacement for std::list that allows fast + * insertion inside, fast deletion at the beginning, and + * maintains sorting? + * @note Constructed with empty structures, which are set to + * proper sizes by init_buffers_(). + * @note State_ only contains read-out values, so we copy-construct + * using the default c'tor. + */ + struct State_ { + + std::vector n_events_; //!< spike counters + SpikelistType incoming_; //!< incoming spikes, sorted + /** Weighted covariance matrix. + * @note Data type is double to accomodate weights. + */ + std::vector > > covariance_; + + /** Unweighted covariance matrix. + */ + std::vector > > count_covariance_; + + State_(); //!< initialize default state + + void get(DictionaryDatum&) const; + + /** + * @param bool if true, force state reset + */ + void set(const DictionaryDatum&, const Parameters_&, bool); + + void reset(const Parameters_&); + }; + + // ------------------------------------------------------------ + + PseudoRecordingDevice device_; + Parameters_ P_; + State_ S_; + }; + + inline + port correlomatrix_detector::connect_sender(SpikeEvent&, port receptor_type) + { + if (receptor_type < 0 || receptor_type > P_.N_channels_-1) + throw UnknownReceptorType(receptor_type, get_name()); + return receptor_type; + } + + inline + void nest::correlomatrix_detector::get_status(DictionaryDatum &d) const + { + device_.get_status(d); + P_.get(d); + S_.get(d); + + (*d)[names::type] = LiteralDatum(names::recorder); + } + + inline + void nest::correlomatrix_detector::set_status(const DictionaryDatum &d) + { + Parameters_ ptmp = P_; + const bool reset_required = ptmp.set(d, *this); + + device_.set_status(d); + P_ = ptmp; + if ( reset_required == true) + S_.reset(P_); + } + +} // namespace + +#endif /* #ifndef CORRELOMATRIX_DETECTOR_H */ diff --git a/models/dc_generator.h b/models/dc_generator.h index a29ac7974d..ca71d0441b 100644 --- a/models/dc_generator.h +++ b/models/dc_generator.h @@ -78,7 +78,6 @@ namespace nest bool has_proxies() const {return false;} - port check_connection(Connection&, port); void get_status(DictionaryDatum &) const; diff --git a/models/gamma_sup_generator.cpp b/models/gamma_sup_generator.cpp index c2481ca601..65998a406e 100644 --- a/models/gamma_sup_generator.cpp +++ b/models/gamma_sup_generator.cpp @@ -47,7 +47,7 @@ nest::gamma_sup_generator::Internal_states_::Internal_states_(size_t num_bins, u nest::ulong_t nest::gamma_sup_generator::Internal_states_::update(double_t transition_prob, librandom::RngPtr rng) { - std::vector n_trans; + std::vector n_trans; // only set from poisson_dev_ og bino_dev_ or 0, thus >= 0 n_trans.resize( occ_.size() ); // go through all states and draw number of transitioning components @@ -57,28 +57,26 @@ nest::ulong_t nest::gamma_sup_generator::Internal_states_::update(double_t trans { /*The binomial distribution converges towards the Poisson distribution as the number of trials goes to infinity while the product np remains fixed. - Therefore the Poisson distribution with parameter λ = np can be used as - an approximation to B(n, p) of the binomial distribution if n is - sufficiently large and p is sufficiently small. According to two rules - of thumb, this approximation is good if n ≥ 20 and p ≤ 0.05, or if - n ≥ 100 and np ≤ 10. Source: + Therefore the Poisson distribution with parameter \lambda = np can be used as + an approximation to B(n, p) of the binomial distribution if n is + sufficiently large and p is sufficiently small. According to two rules + of thumb, this approximation is good if n >= 20 and p <= 0.05, or if + n >= 100 and np <= 10. Source: http://en.wikipedia.org/wiki/Binomial_distribution#Poisson_approximation */ if (( occ_[i] >= 100 && transition_prob <= 0.01 ) || \ ( occ_[i] >= 500 && transition_prob * occ_[i] <= 0.1 )) { poisson_dev_.set_lambda( transition_prob * occ_[i] ); - n_trans[i] = poisson_dev_.uldev(rng); + n_trans[i] = poisson_dev_.ldev(rng); if ( n_trans[i] > occ_[i] ) { n_trans[i] = occ_[i]; } - else - {;} } else { bino_dev_.set_p_n( transition_prob, occ_[i]); - n_trans[i] = bino_dev_.uldev(rng); + n_trans[i] = bino_dev_.ldev(rng); } } else diff --git a/models/gamma_sup_generator.h b/models/gamma_sup_generator.h index af3227e152..7218ae92c7 100644 --- a/models/gamma_sup_generator.h +++ b/models/gamma_sup_generator.h @@ -76,8 +76,6 @@ namespace nest{ public: - typedef Node base; - gamma_sup_generator(); gamma_sup_generator(const gamma_sup_generator&); diff --git a/models/ginzburg_neuron.h b/models/ginzburg_neuron.h index 0dffed83fe..6dd7817a16 100644 --- a/models/ginzburg_neuron.h +++ b/models/ginzburg_neuron.h @@ -68,6 +68,8 @@ namespace nest only sends a spike if a transition of its state occurs. If the state makes an up-transition it sends a spike with multiplicity 2, if a down transition occurs, it sends a spike with multiplicity 1. + The neuron accepts several sources of currents, e.g. from a + noise_generator. Parameters: tau_m double - Membrane time constant (mean inter-update-interval) in ms. diff --git a/models/hh_cond_exp_traub.h b/models/hh_cond_exp_traub.h index 789e08092a..6c74f8a7b8 100644 --- a/models/hh_cond_exp_traub.h +++ b/models/hh_cond_exp_traub.h @@ -113,8 +113,6 @@ SeeAlso: hh_psc_alpha public: - // typedef Node base; - hh_cond_exp_traub(); hh_cond_exp_traub(const hh_cond_exp_traub&); ~hh_cond_exp_traub(); diff --git a/models/hh_psc_alpha.h b/models/hh_psc_alpha.h index 1d40013fdd..693fbcdf68 100644 --- a/models/hh_psc_alpha.h +++ b/models/hh_psc_alpha.h @@ -128,8 +128,6 @@ SeeAlso: hh_cond_exp_traub public: - typedef Node base; - hh_psc_alpha(); hh_psc_alpha(const hh_psc_alpha&); ~hh_psc_alpha(); diff --git a/models/ht_neuron.h b/models/ht_neuron.h index 97556ce0d1..1a4e8dbf9f 100644 --- a/models/ht_neuron.h +++ b/models/ht_neuron.h @@ -1,6 +1,3 @@ -#ifndef HT_NEURON_H -#define HT_NEURON_H - /* * ht_neuron.h * @@ -23,6 +20,9 @@ * */ +#ifndef HT_NEURON_H +#define HT_NEURON_H + #include "archiving_node.h" #include #include diff --git a/models/iaf_chs_2007.cpp b/models/iaf_chs_2007.cpp new file mode 100644 index 0000000000..6cf4c0b966 --- /dev/null +++ b/models/iaf_chs_2007.cpp @@ -0,0 +1,261 @@ +/* + * iaf_chs_2007.cpp + * + * This file is part of NEST. + * + * Copyright (C) 2004 The NEST Initiative + * + * NEST 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 2 of the License, or + * (at your option) any later version. + * + * NEST 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 NEST. If not, see . + * + */ + +#include "exceptions.h" +#include "iaf_chs_2007.h" +#include "network.h" +#include "dict.h" +#include "integerdatum.h" +#include "doubledatum.h" +#include "dictutils.h" +#include "numerics.h" +#include "universal_data_logger_impl.h" + +#include + +/* ---------------------------------------------------------------- + * Recordables map + * ---------------------------------------------------------------- */ + +nest::RecordablesMap nest::iaf_chs_2007::recordablesMap_; + +namespace nest +{ + // Override the create() method with one call to RecordablesMap::insert_() + // for each quantity to be recorded. + template <> + void RecordablesMap::create() + { + // use standard names wherever you can for consistency! + insert_(names::V_m, &iaf_chs_2007::get_V_m_); + } +} + +/* ---------------------------------------------------------------- + * Default constructors defining default parameters and state + * ---------------------------------------------------------------- */ + +nest::iaf_chs_2007::Parameters_::Parameters_() + : tau_epsp_ ( 8.5 ), // in ms + tau_reset_ ( 15.4 ), // in ms + E_L_ ( 0.0 ), // normalized + U_th_ ( 1.0 ), // normalized + U_epsp_ ( 0.77 ), // normalized + U_reset_ ( 2.31 ), // normalized + C_ ( 1.0 ), // Should not be modified + U_noise_ ( 0.0 ), // normalized + noise_ ( ) + +{} + + +nest::iaf_chs_2007::State_::State_() + : i_syn_ex_ ( 0.0 ), + V_syn_ ( 0.0 ), + V_spike_ ( 0.0 ), + V_m_ ( 0.0 ) +{} + +/* ---------------------------------------------------------------- + * Parameter and state extractions and manipulation functions + * ---------------------------------------------------------------- */ + +void nest::iaf_chs_2007::Parameters_::get(DictionaryDatum &d) const +{ + def(d, names::V_reset, U_reset_); + def(d, names::V_epsp, U_epsp_); + def(d, names::tau_epsp, tau_epsp_); + def(d, names::tau_reset, tau_reset_); + def(d, names::V_noise, U_noise_); + (*d)[names::noise] = DoubleVectorDatum(new std::vector(noise_)); + +} + +void nest::iaf_chs_2007::Parameters_::set(const DictionaryDatum &d, State_& s) +{ + updateValue(d, names::V_reset, U_reset_); + updateValue(d, names::V_epsp, U_epsp_); + updateValue(d, names::tau_epsp, tau_epsp_); + updateValue(d, names::tau_reset, tau_reset_); + updateValue(d, names::V_noise, U_noise_); + + const bool updated_noise = updateValue >(d, names::noise, noise_); + if(updated_noise) { + s.position_ = 0; + } + /* + // TODO: How to handle setting U_noise first and noise later and still make sure they are consistent? + if ( U_noise_ > 0 && noise_.empty() ) + throw BadProperty("Noise amplitude larger than zero while noise signal is missing."); + */ + if ( U_epsp_ < 0) + throw BadProperty("EPSP cannot be negative."); + + if ( U_reset_ < 0) + throw BadProperty("Reset potential cannot be negative."); //sign switched above + + if ( tau_epsp_ <= 0 || tau_reset_ <= 0 ) + throw BadProperty("All time constants must be strictly positive."); +} + +void nest::iaf_chs_2007::State_::get(DictionaryDatum &d) const +{ + def(d, names::V_m, V_m_); // Membrane potential +} + +void nest::iaf_chs_2007::State_::set(DictionaryDatum const &d) +{ + updateValue(d, names::V_m, V_m_); +} + +nest::iaf_chs_2007::Buffers_::Buffers_(iaf_chs_2007 &n) + : logger_(n) +{} + +nest::iaf_chs_2007::Buffers_::Buffers_(const Buffers_ &, iaf_chs_2007 &n) + : logger_(n) +{} + +/* ---------------------------------------------------------------- + * Default and copy constructor for node + * ---------------------------------------------------------------- */ + +nest::iaf_chs_2007::iaf_chs_2007() + : Archiving_Node(), + P_(), + S_(), + B_(*this) +{ + recordablesMap_.create(); +} + +nest::iaf_chs_2007::iaf_chs_2007(const iaf_chs_2007 &n) + : Archiving_Node(n), + P_(n.P_), + S_(n.S_), + B_(n.B_, *this) +{} + +/* ---------------------------------------------------------------- + * Node initialization functions + * ---------------------------------------------------------------- */ + +void nest::iaf_chs_2007::init_node_(const Node &proto) +{ + const iaf_chs_2007 &pr = downcast(proto); + P_ = pr.P_; + S_ = pr.S_; +} + +void nest::iaf_chs_2007::init_state_(const Node &proto) +{ + const iaf_chs_2007 &pr = downcast(proto); + S_ = pr.S_; +} + +void nest::iaf_chs_2007::init_buffers_() +{ + B_.spikes_ex_.clear(); // includes resize + B_.currents_.clear(); // includes resize + B_.logger_.reset(); + Archiving_Node::clear_history(); +} + +void nest::iaf_chs_2007::calibrate() +{ + B_.logger_.init(); // ensures initialization in case mm connected after Simulate + + const double h = Time::get_resolution().get_ms(); + + // numbering of state vaiables: i_0 = 0, i_syn_ = 1, V_syn_ = 2, V_spike _= 3, V_m_ = 4 + + // these P are independent + V_.P11ex_ = std::exp(-h/P_.tau_epsp_); + + V_.P22_ = std::exp(-h/P_.tau_epsp_); + + V_.P30_ = std::exp(-h/P_.tau_reset_); + + // these depend on the above. Please do not change the order. + // TODO: use expm1 here to improve accuracy for small timesteps + + V_.P21ex_ = P_.U_epsp_*std::exp(1.0)/(P_.C_) * V_.P11ex_ * h/P_.tau_epsp_; + + V_.P20_ = P_.tau_epsp_/P_.C_*(1.0 - V_.P22_); +} + +void nest::iaf_chs_2007::update(const Time &origin, const long_t from, const long_t to) +{ + assert(to >= 0 && (delay) from < Scheduler::get_min_delay()); + assert(from < to); + + // evolve from timestep 'from' to timestep 'to' with steps of h each + for ( long_t lag = from; lag < to; ++lag ) + { + S_.V_syn_ = S_.V_syn_*V_.P22_ + S_.i_syn_ex_*V_.P21ex_; + + // exponential decaying PSCs + S_.i_syn_ex_ *= V_.P11ex_; + + // the spikes arriving at T+1 have an immediate effect on the state of the neuron + S_.i_syn_ex_ += B_.spikes_ex_.get_value(lag); + + // exponentially decaying ahp + S_.V_spike_ *= V_.P30_; + + double noise_term = P_.U_noise_ > 0.0 && !P_.noise_.empty() ? P_.U_noise_ * P_.noise_[S_.position_++] : 0.0; + + S_.V_m_ = S_.V_syn_ + S_.V_spike_ + noise_term; + + + if ( S_.V_m_ >= P_.U_th_ ) // threshold crossing + { + S_.V_spike_ -= P_.U_reset_; + S_.V_m_ -= P_.U_reset_; + + + + set_spiketime(Time::step(origin.get_steps()+lag+1)); + + SpikeEvent se; + network()->send(*this, se, lag); + } + + // log state data + B_.logger_.record_data(origin.get_steps() + lag); + + } +} + +void nest::iaf_chs_2007::handle(SpikeEvent &e) +{ + assert ( e.get_delay() > 0 ); + + if ( e.get_weight() >= 0.0 ) + B_.spikes_ex_.add_value(e.get_rel_delivery_steps(network()->get_slice_origin()), + e.get_weight() * e.get_multiplicity() ); +} + +void nest::iaf_chs_2007::handle(DataLoggingRequest &e) +{ + B_.logger_.handle(e); +} diff --git a/models/iaf_chs_2007.h b/models/iaf_chs_2007.h new file mode 100644 index 0000000000..c2be8bdefe --- /dev/null +++ b/models/iaf_chs_2007.h @@ -0,0 +1,332 @@ +/* + * iaf_chs_2007.h + * + * This file is part of NEST. + * + * Copyright (C) 2004 The NEST Initiative + * + * NEST 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 2 of the License, or + * (at your option) any later version. + * + * NEST 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 NEST. If not, see . + * + */ + +#ifndef IAF_CHS_2007_H +#define IAF_CHS_2007_H + +#include "nest.h" +#include "event.h" +#include "archiving_node.h" +#include "ring_buffer.h" +#include "connection.h" +#include "universal_data_logger.h" +#include "recordables_map.h" +#include "normal_randomdev.h" + +namespace nest +{ + class Network; + + /* BeginDocumentation + Name: iaf_chs_2007 - Spike-response model used in Carandini et al 2007. + + Description: + The membrane potential is the sum of stereotyped events: the postsynaptic + potentials (V_syn), waveforms that include a spike and the subsequent + after-hyperpolarization (V_spike) and Gaussian-distributed white noise. + + The postsynaptic potential is described by alpha function where where + U_epsp is the maximal amplitude of the EPSP and tau_epsp is the time to + peak of the EPSP. + + The spike waveform is described as a delta peak followed by a membrane + potential reset and exponential decay. U_reset is the magnitude of the + reset/after-hyperpolarization and tau_reset is the time constant of + recovery from this hyperpolarization. + + The linear subthresold dynamics is integrated by the Exact + Integration scheme [1]. The neuron dynamics is solved on the time + grid given by the computation step size. Incoming as well as emitted + spikes are forced to that grid. + + Note: + The way the noise term was implemented in the original model makes it + unsuitable for simulation in NEST. The workaround was to prepare the + noise signal externally prior to simulation. The noise signal, + if present, has to be at least as long as the simulation. + + Parameters: + The following parameters can be set in the status dictionary. + + tau_epsp double - Membrane time constant in ms. + tau_reset double - Refractory time constant in ms. + U_epsp double - Maximum amplitude of the EPSP. Normalized. + U_reset double - Reset value of the membrane potential. Normalized. + U_noise double - Noise scale. Normalized. + noise vector- Noise signal. + + References: + [1] Carandini M, Horton JC, Sincich LC (2007) Thalamic filtering of retinal + spike trains by postsynaptic summation. J Vis 7(14):20,1Ð11. + [2] Rotter S & Diesmann M (1999) Exact simulation of time-invariant linear + systems with applications to neuronal modeling. Biologial Cybernetics + 81:381-402. + + Sends: SpikeEvent + + Receives: SpikeEvent, DataLoggingRequest + + FirstVersion: May 2012 + Author: Thomas Heiberg, Birgit Kriener + */ + + /** + * Neuron model used in Carandini et al 2007. + */ + class iaf_chs_2007: + public Archiving_Node + { + + public: + + iaf_chs_2007(); + iaf_chs_2007(const iaf_chs_2007&); + + /** + * Import sets of overloaded virtual functions. + * We need to explicitly include sets of overloaded + * virtual functions into the current scope. + * According to the SUN C++ FAQ, this is the correct + * way of doing things, although all other compilers + * happily live without. + */ + + using Node::connect_sender; + using Node::handle; + + port check_connection(Connection&, port); + + void handle(SpikeEvent &); + void handle(DataLoggingRequest &); + + port connect_sender(SpikeEvent &, port); + port connect_sender(DataLoggingRequest &, port); + + void get_status(DictionaryDatum &) const; + void set_status(const DictionaryDatum &); + + private: + + void init_node_(const Node& proto); + void init_state_(const Node& proto); + void init_buffers_(); + void calibrate(); + + void update(const Time &, const long_t, const long_t); + + // The next two classes need to be friends to access the State_ class/member + friend class RecordablesMap; + friend class UniversalDataLogger; + + // ---------------------------------------------------------------- + + /** + * State variables of the model. + */ + struct State_ + { + // state variables + double_t i_syn_ex_; // postsynaptic current for exc. inputs, variable 1 + double_t V_syn_; // psp waveform, variable 2 + double_t V_spike_; // post spike reset waveform, variable 3 + double_t V_m_; // membrane potential, variable 4 + + ulong_t position_; + + State_(); //!< Default initialization + + void get(DictionaryDatum &) const; + void set(DictionaryDatum const &); + }; + + // ---------------------------------------------------------------- + + /** + * Independent parameters of the model. + */ + struct Parameters_ + { + + /** Membrane time constant in ms. */ + double_t tau_epsp_; + + /** Refractory time constant in ms. */ + double_t tau_reset_; + + /** Resting potential. Normalized = 0.0. */ + double_t E_L_; + + /** Threshold. Normalized = 1.0. */ + double_t U_th_; + + /** Normalized maximum amplitude of the EPSP. */ + double_t U_epsp_; + + /** Normalized magnitude of the membrane potential reset. */ + double_t U_reset_; + + /** Membrane capacitance. Note: Does not have any function currently. */ + double_t C_; + + /** Noise scale. */ + double_t U_noise_; + + /** Noise signal. */ + std::vector noise_; + + Parameters_(); //!< Sets default parameter values + + void get(DictionaryDatum&) const; //!< Store current values in dictionary + + /** Set values from dictionary. + * @returns Change in reversal potential E_L, to be passed to State_::set() + * @note State is passed so that the position can be reset if the + * noise_ vector has been filled with new data. + */ + void set(const DictionaryDatum&, State_& s); + }; + + + // ---------------------------------------------------------------- + + /** + * Buffers of the model. + */ + struct Buffers_ + { + Buffers_(iaf_chs_2007 &); + Buffers_(const Buffers_ &, iaf_chs_2007 &); + + /** buffers and sums up incoming spikes/currents */ + RingBuffer spikes_ex_; + RingBuffer currents_; + + //! Logger for all analog data + UniversalDataLogger logger_; + }; + + // ---------------------------------------------------------------- + + /** + * Internal variables of the model. + */ + struct Variables_ + { + /** Amplitude of the synaptic current. + This value is chosen such that a post-synaptic potential with + weight one has an amplitude of 1 mV. + @note mog - I assume this, not checked. + */ + // double_t PSCInitialValue_; + + // time evolution operator + double_t P20_; + double_t P11ex_; + double_t P21ex_; + double_t P22_; + double_t P30_; + + librandom::NormalRandomDev normal_dev_; //!< random deviate generator + }; + + // Access functions for UniversalDataLogger ------------------------------- + + //! Read out the real membrane potential + double_t get_V_m_() const { return S_.V_m_ + P_.E_L_; } + + // ---------------------------------------------------------------- + + /** + * @defgroup iaf_psc_exp_data + * Instances of private data structures for the different types + * of data pertaining to the model. + * @note The order of definitions is important for speed. + * @{ + */ + Parameters_ P_; + State_ S_; + Variables_ V_; + Buffers_ B_; + /** @} */ + + //! Mapping of recordables names to access functions + static RecordablesMap recordablesMap_; + }; + + inline + port iaf_chs_2007::check_connection(Connection &c, port receptor_type) + { + SpikeEvent e; + e.set_sender(*this); + c.check_event(e); + return c.get_target()->connect_sender(e, receptor_type); + } + + inline + port iaf_chs_2007::connect_sender(SpikeEvent&, port receptor_type) + { + if (receptor_type != 0) + throw UnknownReceptorType(receptor_type, get_name()); + return 0; + } + + inline + port iaf_chs_2007::connect_sender(DataLoggingRequest &dlr, + port receptor_type) + { + if (receptor_type != 0) + throw UnknownReceptorType(receptor_type, get_name()); + return B_.logger_.connect_logging_device(dlr, recordablesMap_); + } + + inline + void iaf_chs_2007::get_status(DictionaryDatum &d) const + { + P_.get(d); + S_.get(d); + Archiving_Node::get_status(d); + + (*d)[names::recordables] = recordablesMap_.get_list(); + } + + inline + void iaf_chs_2007::set_status(const DictionaryDatum &d) + { + Parameters_ ptmp = P_; // temporary copy in case of errors + ptmp.set(d, S_); + State_ stmp = S_; // temporary copy in case of errors + stmp.set(d); // throws if BadProperty + + // We now know that (ptmp, stmp) are consistent. We do not + // write them back to (P_, S_) before we are also sure that + // the properties to be set in the parent class are internally + // consistent. + Archiving_Node::set_status(d); + + // if we get here, temporaries contain consistent set of properties + P_ = ptmp; + S_ = stmp; + } + +} // namespace + +#endif // IAF_CHS_2007_H diff --git a/models/iaf_chxk_2008.cpp b/models/iaf_chxk_2008.cpp new file mode 100644 index 0000000000..a24a22e6cd --- /dev/null +++ b/models/iaf_chxk_2008.cpp @@ -0,0 +1,412 @@ +/* + * iaf_chxk_2008.cpp + * + * This file is part of NEST. + * + * Copyright (C) 2004 The NEST Initiative + * + * NEST 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 2 of the License, or + * (at your option) any later version. + * + * NEST 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 NEST. If not, see . + * + */ + +#include "iaf_chxk_2008.h" + +#ifdef HAVE_GSL + +#include "exceptions.h" +#include "network.h" +#include "dict.h" +#include "integerdatum.h" +#include "doubledatum.h" +#include "dictutils.h" +#include "numerics.h" +#include "universal_data_logger_impl.h" +#include + +#include +#include +#include + +/* ---------------------------------------------------------------- + * Recordables map + * ---------------------------------------------------------------- */ + +nest::RecordablesMap nest::iaf_chxk_2008::recordablesMap_; + +namespace nest // template specialization must be placed in namespace +{ +/* + * Override the create() method with one call to RecordablesMap::insert_() + * for each quantity to be recorded. + */ +template<> +void RecordablesMap::create() { + // use standard names wherever you can for consistency! + insert_(names::V_m, &iaf_chxk_2008::get_y_elem_); + insert_(names::g_ex, &iaf_chxk_2008::get_y_elem_< + iaf_chxk_2008::State_::G_EXC>); + insert_(names::g_in, &iaf_chxk_2008::get_y_elem_< + iaf_chxk_2008::State_::G_INH>); + insert_(names::g_ahp, &iaf_chxk_2008::get_y_elem_< + iaf_chxk_2008::State_::G_AHP>); + + insert_("I_syn_exc", &iaf_chxk_2008::get_I_syn_exc_); + insert_("I_syn_inh", &iaf_chxk_2008::get_I_syn_inh_); + insert_("I_ahp", &iaf_chxk_2008::get_I_ahp_); +} +} + +/* ---------------------------------------------------------------- + * Iteration function + * ---------------------------------------------------------------- */ + +extern "C" inline int nest::iaf_chxk_2008_dynamics(double, const double y[], + double f[], void* pnode) { + // a shorthand + typedef nest::iaf_chxk_2008::State_ S; + + // get access to node so we can almost work as in a member function + assert(pnode); + const nest::iaf_chxk_2008& node = + *(reinterpret_cast (pnode)); + + // y[] here is---and must be---the state vector supplied by the integrator, + // not the state vector in the node, node.S_.y[]. + + // The following code is verbose for the sake of clarity. We assume that a + // good compiler will optimize the verbosity away ... + const double_t I_syn_exc = y[S::G_EXC] * (y[S::V_M] - node.P_.E_ex); + const double_t I_syn_inh = y[S::G_INH] * (y[S::V_M] - node.P_.E_in); + const double_t I_ahp = y[S::G_AHP] * (y[S::V_M] - node.P_.E_ahp); + const double_t I_leak = node.P_.g_L * (y[S::V_M] - node.P_.E_L); + + // dV_m/dt + f[S::V_M] = (-I_leak - I_syn_exc - I_syn_inh - I_ahp + node.B_.I_stim_ + + node.P_.I_e) / node.P_.C_m; + + // d dg_exc/dt, dg_exc/dt + f[S::DG_EXC] = -y[S::DG_EXC] / node.P_.tau_synE; + f[S::G_EXC] = y[S::DG_EXC] - (y[S::G_EXC] / node.P_.tau_synE); + + // d dg_inh/dt, dg_inh/dt + f[S::DG_INH] = -y[S::DG_INH] / node.P_.tau_synI; + f[S::G_INH] = y[S::DG_INH] - (y[S::G_INH] / node.P_.tau_synI); + + // d dg_ahp/dt, dg_ahp/dt + f[S::DG_AHP] = -y[S::DG_AHP] / node.P_.tau_ahp; + f[S::G_AHP] = y[S::DG_AHP] - (y[S::G_AHP] / node.P_.tau_ahp); + + return GSL_SUCCESS; +} + +/* ---------------------------------------------------------------- + * Default constructors defining default parameters and state + * ---------------------------------------------------------------- */ + +nest::iaf_chxk_2008::Parameters_::Parameters_() : + + // Default values chosen based on values found in + // Alex Casti's simulator + V_th(-45.0), // mV + g_L(100.0), // nS + C_m(1000.0), // pF + E_ex(20.0), // mV + E_in(-90.0), // mV + E_L(-60.0), // mV + tau_synE(1.0), // ms + tau_synI(1.0), // ms + I_e(0.0), // pA + tau_ahp(0.5), // ms + g_ahp(443.8), //nS + E_ahp(-95.0), // mV + ahp_bug(false) + +{ + recordablesMap_.create(); +} + +nest::iaf_chxk_2008::State_::State_(const Parameters_& p) : + r(0) { + y[V_M] = p.E_L; // initialize to reversal potential + for (size_t i = 2; i < STATE_VEC_SIZE; ++i) + y[i] = 0; +} + +nest::iaf_chxk_2008::State_::State_(const State_& s) : + r(s.r) { + for (size_t i = 0; i < STATE_VEC_SIZE; ++i) + y[i] = s.y[i]; +} + +nest::iaf_chxk_2008::State_& nest::iaf_chxk_2008::State_::operator=( + const State_& s) { + if (this == &s) // avoid assignment to self + return *this; + + for (size_t i = 0; i < STATE_VEC_SIZE; ++i) + y[i] = s.y[i]; + + r = s.r; + return *this; +} + +nest::iaf_chxk_2008::Buffers_::Buffers_(iaf_chxk_2008& n) : + logger_(n), s_(0), c_(0), e_(0) { + // Initialization of the remaining members is deferred to + // init_buffers_(). +} + +nest::iaf_chxk_2008::Buffers_::Buffers_(const Buffers_&, iaf_chxk_2008& n) : + logger_(n), s_(0), c_(0), e_(0) { + // Initialization of the remaining members is deferred to + // init_buffers_(). +} + +/* ---------------------------------------------------------------- + * Parameter and state extractions and manipulation functions + * ---------------------------------------------------------------- */ + +void nest::iaf_chxk_2008::Parameters_::get(DictionaryDatum &d) const { + def (d, names::V_th, V_th); + def (d, names::g_L, g_L); + def (d, names::C_m, C_m); + def (d, names::E_ex, E_ex); + def (d, names::E_in, E_in); + def (d, names::E_L, E_L); + def (d, names::tau_syn_ex, tau_synE); + def (d, names::tau_syn_in, tau_synI); + def (d, names::I_e, I_e); + def (d, names::tau_ahp, tau_ahp); + def (d, names::E_ahp, E_ahp); + def (d, names::g_ahp, g_ahp); + def (d, "ahp_bug", ahp_bug); +} + +void nest::iaf_chxk_2008::Parameters_::set(const DictionaryDatum& d) { + // allow setting the membrane potential + updateValue (d, names::V_th, V_th); + updateValue (d, names::g_L, g_L); + updateValue (d, names::C_m, C_m); + updateValue (d, names::E_ex, E_ex); + updateValue (d, names::E_in, E_in); + updateValue (d, names::E_L, E_L); + updateValue (d, names::tau_syn_ex, tau_synE); + updateValue (d, names::tau_syn_in, tau_synI); + updateValue (d, names::I_e, I_e); + updateValue (d, names::tau_ahp, tau_ahp); + updateValue (d, names::E_ahp, E_ahp); + updateValue (d, names::g_ahp, g_ahp); + updateValue (d, "ahp_bug", ahp_bug); + + if (C_m <= 0) + throw BadProperty("Capacitance must be strictly positive."); + + if (tau_synE <= 0 || tau_synI <= 0 || tau_ahp <= 0) + throw BadProperty("All time constants must be strictly positive."); +} + +void nest::iaf_chxk_2008::State_::get(DictionaryDatum &d) const { + def (d, names::V_m, y[V_M]); // Membrane potential +} + +void nest::iaf_chxk_2008::State_::set(const DictionaryDatum& d, + const Parameters_&) { + updateValue (d, names::V_m, y[V_M]); +} + +/* ---------------------------------------------------------------- + * Default and copy constructor for node, and destructor + * ---------------------------------------------------------------- */ + +nest::iaf_chxk_2008::iaf_chxk_2008() : + Archiving_Node(), P_(), S_(P_), B_(*this) { +} + +nest::iaf_chxk_2008::iaf_chxk_2008(const iaf_chxk_2008& n) : + Archiving_Node(n), P_(n.P_), S_(n.S_), B_(n.B_, *this) { +} + +nest::iaf_chxk_2008::~iaf_chxk_2008() { + // GSL structs may not have been allocated, so we need to protect destruction + if (B_.s_) + gsl_odeiv_step_free(B_.s_); + if (B_.c_) + gsl_odeiv_control_free(B_.c_); + if (B_.e_) + gsl_odeiv_evolve_free(B_.e_); +} + +/* ---------------------------------------------------------------- + * Node initialization functions + * ---------------------------------------------------------------- */ + +void nest::iaf_chxk_2008::init_state_(const Node& proto) { + const iaf_chxk_2008& pr = downcast (proto); + S_ = pr.S_; +} + +void nest::iaf_chxk_2008::init_buffers_() { + Archiving_Node::clear_history(); + + B_.spike_exc_.clear(); // includes resize + B_.spike_inh_.clear(); // includes resize + B_.currents_.clear(); // includes resize + + B_.logger_.reset(); + + B_.step_ = Time::get_resolution().get_ms(); + B_.IntegrationStep_ = B_.step_; + + static const gsl_odeiv_step_type* T1 = gsl_odeiv_step_rkf45; + + if (B_.s_ == 0) + B_.s_ = gsl_odeiv_step_alloc(T1, State_::STATE_VEC_SIZE); + else + gsl_odeiv_step_reset(B_.s_); + + if (B_.c_ == 0) + B_.c_ = gsl_odeiv_control_y_new(1e-3, 0.0); + else + gsl_odeiv_control_init(B_.c_, 1e-3, 0.0, 1.0, 0.0); + + if (B_.e_ == 0) + B_.e_ = gsl_odeiv_evolve_alloc(State_::STATE_VEC_SIZE); + else + gsl_odeiv_evolve_reset(B_.e_); + + B_.sys_.function = iaf_chxk_2008_dynamics; + B_.sys_.jacobian = NULL; + B_.sys_.dimension = State_::STATE_VEC_SIZE; + B_.sys_.params = reinterpret_cast (this); + + B_.I_stim_ = 0.0; +} + +void nest::iaf_chxk_2008::calibrate() { + B_.logger_.init(); // ensures initialization in case mm connected after Simulate + + V_.PSConInit_E = 1.0 * numerics::e / P_.tau_synE; + V_.PSConInit_I = 1.0 * numerics::e / P_.tau_synI; + V_.PSConInit_AHP = P_.g_ahp * numerics::e / P_.tau_ahp; +} + +/* ---------------------------------------------------------------- + * Update and spike handling functions + * ---------------------------------------------------------------- */ + +void nest::iaf_chxk_2008::update(Time const & origin, const long_t from, + const long_t to) { + + assert(to >= 0 && (delay) from < Scheduler::get_min_delay()); + assert(from < to); + + for (long_t lag = from; lag < to; ++lag) { + + double t = 0.0; + + // remember membrane potential at beginning of step + // to check for *crossing* + const double vm_prev = S_.y[State_::V_M]; + + // numerical integration with adaptive step size control: + // ------------------------------------------------------ + // gsl_odeiv_evolve_apply performs only a single numerical + // integration step, starting from t and bounded by step; + // the while-loop ensures integration over the whole simulation + // step (0, step] if more than one integration step is needed due + // to a small integration step size; + // note that (t+IntegrationStep > step) leads to integration over + // (t, step] and afterwards setting t to step, but it does not + // enforce setting IntegrationStep to step-t; this is of advantage + // for a consistent and efficient integration across subsequent + // simulation intervals + while (t < B_.step_) { + const int status = gsl_odeiv_evolve_apply(B_.e_, B_.c_, B_.s_, + &B_.sys_, // system of ODE + &t, // from t + B_.step_, // to t <= step + &B_.IntegrationStep_, // integration step size + S_.y); // neuronal state + + + if (status != GSL_SUCCESS) + throw GSLSolverFailure(get_name(), status); + } + // neuron should spike on threshold crossing only. + if ( vm_prev < P_.V_th && S_.y[State_::V_M] >= P_.V_th) { + // neuron is not absolute refractory + + // Find precise spike time using linear interpolation + double_t sigma = (S_.y[State_::V_M] - P_.V_th) * B_.step_ / (S_.y[State_::V_M] - vm_prev); + + double_t alpha = exp(-sigma/P_.tau_ahp); + + double_t delta_g_ahp = V_.PSConInit_AHP * sigma * alpha; + double_t delta_dg_ahp = V_.PSConInit_AHP * alpha; + + if(P_.ahp_bug == true) { + // Bug in original code ignores AHP conductance from previous spikes + S_.y[State_::G_AHP] = delta_g_ahp; + S_.y[State_::DG_AHP] = delta_dg_ahp; + } else { + S_.y[State_::G_AHP] += delta_g_ahp; + S_.y[State_::DG_AHP] += delta_dg_ahp; + } + + // log spike with Archiving_Node + set_spiketime(Time::step(origin.get_steps() + lag + 1)); + + SpikeEvent se; + se.set_offset(sigma); + network()->send(*this, se, lag); + } + + // add incoming spikes + S_.y[State_::DG_EXC] += B_.spike_exc_.get_value(lag) * V_.PSConInit_E; + S_.y[State_::DG_INH] += B_.spike_inh_.get_value(lag) * V_.PSConInit_I; + + // set new input current + B_.I_stim_ = B_.currents_.get_value(lag); + + // log state data + B_.logger_.record_data(origin.get_steps() + lag); + + } +} + +void nest::iaf_chxk_2008::handle(SpikeEvent & e) { + assert(e.get_delay() > 0); + + if (e.get_weight() > 0.0) + B_.spike_exc_.add_value(e.get_rel_delivery_steps( + network()->get_slice_origin()), e.get_weight() + * e.get_multiplicity()); + else + B_.spike_inh_.add_value(e.get_rel_delivery_steps( + network()->get_slice_origin()), -e.get_weight() + * e.get_multiplicity()); // ensure conductance is positive +} + +void nest::iaf_chxk_2008::handle(CurrentEvent& e) { + assert(e.get_delay() > 0); + + // add weighted current; HEP 2002-10-04 + B_.currents_.add_value(e.get_rel_delivery_steps( + network()->get_slice_origin()), e.get_weight() * e.get_current()); +} + +void nest::iaf_chxk_2008::handle(DataLoggingRequest& e) { + B_.logger_.handle(e); +} +#endif //HAVE_GSL diff --git a/models/iaf_chxk_2008.h b/models/iaf_chxk_2008.h new file mode 100644 index 0000000000..15931b084d --- /dev/null +++ b/models/iaf_chxk_2008.h @@ -0,0 +1,387 @@ +/* + * iaf_chxk_2008.h + * + * This file is part of NEST. + * + * Copyright (C) 2004 The NEST Initiative + * + * NEST 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 2 of the License, or + * (at your option) any later version. + * + * NEST 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 NEST. If not, see . + * + */ + +#ifndef IAF_CHXK_2008_H +#define IAF_CHXK_2008_H + +#include "config.h" + +#ifdef HAVE_GSL + +#include "nest.h" +#include "event.h" +#include "archiving_node.h" +#include "ring_buffer.h" +#include "connection.h" +#include "universal_data_logger.h" +#include "recordables_map.h" + +#include +#include +#include + +/* BeginDocumentation +Name: iaf_chxk_2008 - Conductance based leaky integrate-and-fire neuron model used in +Casti et al 2008. + +Description: +iaf_chxk_2008 is an implementation of a spiking neuron using IAF dynamics with +conductance-based synapses [1]. It is modeled after iaf_cond_alpha with the addition +of after hyperpolarization current instead of a membrane potential reset. +Incoming spike events induce a post-synaptic change +of conductance modeled by an alpha function. The alpha function +is normalized such that an event of weight 1.0 results in a peak current of 1 nS +at t = tau_syn. + +Parameters: +The following parameters can be set in the status dictionary. + +V_m double - Membrane potential in mV +E_L double - Leak reversal potential in mV. +C_m double - Capacity of the membrane in pF +V_th double - Spike threshold in mV. +E_ex double - Excitatory reversal potential in mV. +E_in double - Inhibitory reversal potential in mV. +g_L double - Leak conductance in nS. +tau_ex double - Rise time of the excitatory synaptic alpha function in ms. +tau_in double - Rise time of the inhibitory synaptic alpha function in ms. +I_e double - Constant input current in pA. +tau_ahp double - Afterhyperpolarization (AHP) time constant in ms. +E_ahp double - AHP potential in mV. +g_ahp double - AHP conductance in nS. +ahp_bug bool - Defaults to false. If true, behaves like original model implementation. + +References: +[1] Casti A, Hayot F, Xiao Y, and Kaplan E (2008) A simple model of retina-LGN transmission. + J Comput Neurosci 24:235-252. + +Sends: SpikeEvent + +Receives: SpikeEvent, CurrentEvent + +Author: Heiberg + +SeeAlso: iaf_cond_alpha +*/ + +namespace nest +{ + /** + * Function computing right-hand side of ODE for GSL solver. + * @note Must be declared here so we can befriend it in class. + * @note Must have C-linkage for passing to GSL. Internally, it is + * a first-class C++ function, but cannot be a member function + * because of the C-linkage. + * @note No point in declaring it inline, since it is called + * through a function pointer. + * @param void* Pointer to model neuron instance. + */ + extern "C" + int iaf_chxk_2008_dynamics (double, const double*, double*, void*); + + /** + * Integrate-and-fire neuron model with two conductance-based synapses. + */ + class iaf_chxk_2008 : public Archiving_Node + { + + // Boilerplate function declarations -------------------------------- + + public: + + iaf_chxk_2008(); + iaf_chxk_2008(const iaf_chxk_2008&); + ~iaf_chxk_2008(); + + /* + * Import all overloaded virtual functions that we + * override in this class. For background information, + * see http://www.gotw.ca/gotw/005.htm. + */ + + using Node::connect_sender; + using Node::handle; + + port check_connection(Connection&, port); + + bool is_off_grid() const {return true;} // uses off_grid events + port connect_sender(SpikeEvent &, port); + port connect_sender(CurrentEvent &, port); + port connect_sender(DataLoggingRequest &, port); + + void handle(SpikeEvent &); + void handle(CurrentEvent &); + void handle(DataLoggingRequest &); + + void get_status(DictionaryDatum &) const; + void set_status(const DictionaryDatum &); + + private: + void init_state_(const Node& proto); + void init_buffers_(); + void calibrate(); + void update(Time const &, const long_t, const long_t); + + // END Boilerplate function declarations ---------------------------- + + // Friends -------------------------------------------------------- + + // make dynamics function quasi-member + friend int iaf_chxk_2008_dynamics(double, const double*, double*, void*); + + // The next two classes need to be friends to access the State_ class/member + friend class RecordablesMap; + friend class UniversalDataLogger; + + private: + + // Parameters class ------------------------------------------------- + + //! Model parameters + struct Parameters_ { + double_t V_th; //!< Threshold Potential in mV + double_t g_L; //!< Leak Conductance in nS + double_t C_m; //!< Membrane Capacitance in pF + double_t E_ex; //!< Excitatory reversal Potential in mV + double_t E_in; //!< Inhibitory reversal Potential in mV + double_t E_L; //!< Leak reversal Potential (a.k.a. resting potential) in mV + double_t tau_synE; //!< Synaptic Time Constant Excitatory Synapse in ms + double_t tau_synI; //!< Synaptic Time Constant for Inhibitory Synapse in ms + double_t I_e; //!< Constant Current in pA + double_t tau_ahp; //!< Afterhyperpolarization (AHP) time constant + double_t g_ahp; //!< AHP conductance + double_t E_ahp; //!< AHP potential + bool ahp_bug; //!< If true, discard AHP conductance value from previous spikes + Parameters_(); //!< Set default parameter values + + void get(DictionaryDatum&) const; //!< Store current values in dictionary + void set(const DictionaryDatum&); //!< Set values from dictionary + }; + + // State variables class -------------------------------------------- + + /** + * State variables of the model. + * + * State variables consist of the state vector for the subthreshold + * dynamics and the refractory count. The state vector must be a + * C-style array to be compatible with GSL ODE solvers. + * + * @note Copy constructor and assignment operator are required because + * of the C-style array. + */ + public: + struct State_ { + + //! Symbolic indices to the elements of the state vector y + enum StateVecElems { V_M = 0, + DG_EXC, G_EXC, + DG_INH, G_INH, + DG_AHP, G_AHP, + STATE_VEC_SIZE }; + + //! state vector, must be C-array for GSL solver + double_t y[STATE_VEC_SIZE]; + + //!< number of refractory steps remaining + int_t r; + + State_(const Parameters_&); //!< Default initialization + State_(const State_&); + State_& operator=(const State_&); + + void get(DictionaryDatum&) const; //!< Store current values in dictionary + + /** + * Set state from values in dictionary. + * Requires Parameters_ as argument to, e.g., check bounds.' + */ + void set(const DictionaryDatum&, const Parameters_&); + }; + private: + + // Buffers class -------------------------------------------------------- + + /** + * Buffers of the model. + * Buffers are on par with state variables in terms of persistence, + * i.e., initialized only upon first Simulate call after ResetKernel + * or ResetNetwork, but are implementation details hidden from the user. + */ + struct Buffers_ { + Buffers_(iaf_chxk_2008&); //! logger_; + + /** buffers and sums up incoming spikes/currents */ + RingBuffer spike_exc_; + RingBuffer spike_inh_; + RingBuffer currents_; + + /* GSL ODE stuff */ + gsl_odeiv_step* s_; //!< stepping function + gsl_odeiv_control* c_; //!< adaptive step size control function + gsl_odeiv_evolve* e_; //!< evolution function + gsl_odeiv_system sys_; //!< struct describing system + + // IntergrationStep_ should be reset with the neuron on ResetNetwork, + // but remain unchanged during calibration. Since it is initialized with + // step_, and the resolution cannot change after nodes have been created, + // it is safe to place both here. + double_t step_; //!< step size in ms + double IntegrationStep_;//!< current integration time step, updated by GSL + + /** + * Input current injected by CurrentEvent. + * This variable is used to transport the current applied into the + * _dynamics function computing the derivative of the state vector. + * It must be a part of Buffers_, since it is initialized once before + * the first simulation, but not modified before later Simulate calls. + */ + double_t I_stim_; + }; + + // Variables class ------------------------------------------------------- + + /** + * Internal variables of the model. + * Variables are re-initialized upon each call to Simulate. + */ + struct Variables_ { + /** + * Impulse to add to DG_EXC on spike arrival to evoke unit-amplitude + * conductance excursion. + */ + double_t PSConInit_E; + + /** + * Impulse to add to DG_INH on spike arrival to evoke unit-amplitude + * conductance excursion. + */ + double_t PSConInit_I; + + /** + * Impulse to add to DG_AHP on spike generation to evoke unit-amplitude + * conductance excursion. + */ + double_t PSConInit_AHP; + }; + + // Access functions for UniversalDataLogger ------------------------------- + + //! Read out state vector elements, used by UniversalDataLogger + template + double_t get_y_elem_() const { return S_.y[elem]; } + + //! Read out remaining refractory time, used by UniversalDataLogger + double_t get_r_() const { return Time::get_resolution().get_ms() * S_.r; } + + double_t get_I_syn_exc_() const { return S_.y[State_::G_EXC] * (S_.y[State_::V_M] - P_.E_ex); } + double_t get_I_syn_inh_() const { return S_.y[State_::G_INH] * (S_.y[State_::V_M] - P_.E_in); } + double_t get_I_ahp_() const { return S_.y[State_::G_AHP] * (S_.y[State_::V_M] - P_.E_ahp); } + + + // Data members ----------------------------------------------------------- + + // keep the order of these lines, seems to give best performance + Parameters_ P_; + State_ S_; + Variables_ V_; + Buffers_ B_; + + //! Mapping of recordables names to access functions + static RecordablesMap recordablesMap_; + }; + + + // Boilerplate inline function definitions ---------------------------------- + + inline + port iaf_chxk_2008::check_connection(Connection& c, port receptor_type) + { + SpikeEvent e; + e.set_sender(*this); + c.check_event(e); + return c.get_target()->connect_sender(e, receptor_type); + } + + inline + port iaf_chxk_2008::connect_sender(SpikeEvent&, port receptor_type) + { + if (receptor_type != 0) + throw UnknownReceptorType(receptor_type, get_name()); + return 0; + } + + inline + port iaf_chxk_2008::connect_sender(CurrentEvent&, port receptor_type) + { + if (receptor_type != 0) + throw UnknownReceptorType(receptor_type, get_name()); + return 0; + } + + inline + port iaf_chxk_2008::connect_sender(DataLoggingRequest& dlr, + port receptor_type) + { + if (receptor_type != 0) + throw UnknownReceptorType(receptor_type, get_name()); + return B_.logger_.connect_logging_device(dlr, recordablesMap_); + } + + inline + void iaf_chxk_2008::get_status(DictionaryDatum &d) const + { + P_.get(d); + S_.get(d); + Archiving_Node::get_status(d); + + (*d)[names::recordables] = recordablesMap_.get_list(); + } + + inline + void iaf_chxk_2008::set_status(const DictionaryDatum &d) + { + Parameters_ ptmp = P_; // temporary copy in case of errors + ptmp.set(d); // throws if BadProperty + State_ stmp = S_; // temporary copy in case of errors + stmp.set(d, ptmp); // throws if BadProperty + + // We now know that (ptmp, stmp) are consistent. We do not + // write them back to (P_, S_) before we are also sure that + // the properties to be set in the parent class are internally + // consistent. + Archiving_Node::set_status(d); + + // if we get here, temporaries contain consistent set of properties + P_ = ptmp; + S_ = stmp; + } + +} // namespace + + +#endif //HAVE_GSL +#endif //IAF_CHXK_2008_H diff --git a/models/iaf_cond_alpha.h b/models/iaf_cond_alpha.h index 140b3b28b4..990aa6f70a 100644 --- a/models/iaf_cond_alpha.h +++ b/models/iaf_cond_alpha.h @@ -73,12 +73,12 @@ Receives: SpikeEvent, CurrentEvent, DataLoggingRequest Meffin, H., Burkitt, A. N., & Grayden, D. B. (2004). An analytical model for the large, fluctuating synaptic conductance state typical of -neocortical neurons in vivo. J. Comput. Neurosci., 16, 159–175. +neocortical neurons in vivo. J. Comput. Neurosci., 16, 159-175. Bernander, O ., Douglas, R. J., Martin, K. A. C., & Koch, C. (1991). Synaptic background activity influences spatiotemporal integration in single pyramidal cells. Proc. Natl. Acad. Sci. USA, 88(24), -11569–11573. +11569-11573. Kuhn, Aertsen, Rotter (2004) Neuronal Integration of Synaptic Input in the Fluctuation- Driven Regime. Jneurosci 24(10) 2345-2356 diff --git a/models/iaf_cond_exp.h b/models/iaf_cond_exp.h index 6ce769a407..2de88406fd 100644 --- a/models/iaf_cond_exp.h +++ b/models/iaf_cond_exp.h @@ -72,7 +72,7 @@ Receives: SpikeEvent, CurrentEvent, DataLoggingRequest Meffin, H., Burkitt, A. N., & Grayden, D. B. (2004). An analytical model for the large, fluctuating synaptic conductance state typical of -neocortical neurons in vivo. J. Comput. Neurosci., 16, 159–175. +neocortical neurons in vivo. J. Comput. Neurosci., 16, 159-175. Author: Sven Schrader @@ -99,8 +99,6 @@ namespace nest public: - typedef Node base; - iaf_cond_exp(); iaf_cond_exp(const iaf_cond_exp&); ~iaf_cond_exp(); diff --git a/models/iaf_cond_exp_sfa_rr.h b/models/iaf_cond_exp_sfa_rr.h index d5a5ac63b2..211b19053b 100644 --- a/models/iaf_cond_exp_sfa_rr.h +++ b/models/iaf_cond_exp_sfa_rr.h @@ -89,7 +89,7 @@ Receives: SpikeEvent, CurrentEvent, DataLoggingRequest Meffin, H., Burkitt, A. N., & Grayden, D. B. (2004). An analytical model for the large, fluctuating synaptic conductance state typical of -neocortical neurons in vivo. J. Comput. Neurosci., 16, 159–175. +neocortical neurons in vivo. J. Comput. Neurosci., 16, 159-175. Dayan, P. and Abbott, L. F. (2001). Theoretical Neuroscience, MIT Press (p166) diff --git a/models/iaf_neuron.h b/models/iaf_neuron.h index ecc5eca80b..bac5448069 100644 --- a/models/iaf_neuron.h +++ b/models/iaf_neuron.h @@ -128,8 +128,6 @@ SeeAlso: iaf_psc_alpha, testsuite::test_iaf public: - typedef Node base; - iaf_neuron(); iaf_neuron(const iaf_neuron&); @@ -137,7 +135,6 @@ SeeAlso: iaf_psc_alpha, testsuite::test_iaf * Import sets of overloaded virtual functions. * @see Technical Issues / Virtual Functions: Overriding, Overloading, and Hiding */ - using Node::connect_sender; using Node::handle; diff --git a/models/iaf_psc_alpha.cpp b/models/iaf_psc_alpha.cpp index 77d3619ea4..a5f3fbc671 100644 --- a/models/iaf_psc_alpha.cpp +++ b/models/iaf_psc_alpha.cpp @@ -46,8 +46,10 @@ namespace nest { // use standard names whereever you can for consistency! insert_(names::V_m, &iaf_psc_alpha::get_V_m_); - insert_("weighted_spikes_ex", &iaf_psc_alpha::get_weighted_spikes_ex_); - insert_("weighted_spikes_in", &iaf_psc_alpha::get_weighted_spikes_in_); + insert_(names::weighted_spikes_ex, &iaf_psc_alpha::get_weighted_spikes_ex_); + insert_(names::weighted_spikes_in, &iaf_psc_alpha::get_weighted_spikes_in_); + insert_(names::input_currents_ex, &iaf_psc_alpha::get_input_currents_ex_); + insert_(names::input_currents_in, &iaf_psc_alpha::get_input_currents_in_); } /* ---------------------------------------------------------------- diff --git a/models/iaf_psc_alpha.h b/models/iaf_psc_alpha.h index 2b21832064..db96e79e24 100644 --- a/models/iaf_psc_alpha.h +++ b/models/iaf_psc_alpha.h @@ -287,6 +287,7 @@ namespace nest double_t weighted_spikes_ex_; double_t weighted_spikes_in_; + }; // Access functions for UniversalDataLogger ------------------------------- @@ -296,6 +297,8 @@ namespace nest double_t get_weighted_spikes_ex_() const { return V_.weighted_spikes_ex_; } double_t get_weighted_spikes_in_() const { return V_.weighted_spikes_in_; } + double_t get_input_currents_ex_() const { return S_.y1_ex_; } + double_t get_input_currents_in_() const { return S_.y1_in_; } // Data members ----------------------------------------------------------- diff --git a/models/iaf_psc_alpha_multisynapse.cpp b/models/iaf_psc_alpha_multisynapse.cpp index 51112ad62f..385efa620c 100644 --- a/models/iaf_psc_alpha_multisynapse.cpp +++ b/models/iaf_psc_alpha_multisynapse.cpp @@ -64,9 +64,8 @@ iaf_psc_alpha_multisynapse::Parameters_::Parameters_() V_reset_ (-70.0-U0_), // mV, rel to U0_ Theta_ (-55.0-U0_), // mV, rel to U0_ LowerBound_ (-std::numeric_limits::infinity()), - num_of_receptors_ (0) + has_connections_ ( false ) { - receptor_types_.clear(); tau_syn_.clear(); } @@ -93,13 +92,13 @@ void iaf_psc_alpha_multisynapse::Parameters_::get(DictionaryDatum &d) const def(d, names::C_m, C_); def(d, names::tau_m, Tau_); def(d, names::t_ref, TauR_); - def(d,"n_synapses", num_of_receptors_); def(d, names::V_min, LowerBound_+U0_); + def(d,"n_synapses", num_of_receptors_); + def(d, names::has_connections, has_connections_); ArrayDatum tau_syn_ad(tau_syn_); def(d,"tau_syn", tau_syn_ad); - - (*d)["receptor_types"] = IntVectorDatum(new std::vector(receptor_types_)); + } double iaf_psc_alpha_multisynapse::Parameters_::set(const DictionaryDatum& d) @@ -135,17 +134,13 @@ double iaf_psc_alpha_multisynapse::Parameters_::set(const DictionaryDatum& d) if ( Tau_ <= 0. ) throw BadProperty("Membrane time constant must be > 0."); - if (updateValue(d, "n_synapses", num_of_receptors_)) - tau_syn_.resize(num_of_receptors_, 2.0); - std::vector tau_tmp; if (updateValue >(d, "tau_syn", tau_tmp)) { - if (tau_tmp.size() != num_of_receptors_) - throw DimensionMismatch(num_of_receptors_, tau_tmp.size()); - for (size_t i = 0; i < tau_tmp.size(); ++i) { + if (tau_tmp.size() < tau_syn_.size() && has_connections_ == true) + throw BadProperty("The neuron has connections, therefore the number of ports cannot be reduced."); if (tau_tmp[i] <= 0) throw BadProperty("All synaptic time constants must be > 0."); if (tau_tmp[i] == Tau_) @@ -153,6 +148,7 @@ double iaf_psc_alpha_multisynapse::Parameters_::set(const DictionaryDatum& d) } tau_syn_ = tau_tmp; + num_of_receptors_ = tau_syn_.size(); } if ( TauR_ < 0. ) @@ -161,8 +157,6 @@ double iaf_psc_alpha_multisynapse::Parameters_::set(const DictionaryDatum& d) if ( V_reset_ >= Theta_ ) throw BadProperty("Reset potential must be smaller than threshold."); - updateValue >(d, "receptor_types", receptor_types_); - return delta_EL; } @@ -233,31 +227,29 @@ void iaf_psc_alpha_multisynapse::calibrate() const double h = Time::get_resolution().get_ms(); - V_.receptor_types_size_ = P_.receptor_types_.size(); - - // if n_synapses has been Decreased with SetStatus, force new dimension. - if (P_.num_of_receptors_ < V_.receptor_types_size_){ - V_.receptor_types_size_ = P_.num_of_receptors_; - P_.receptor_types_.resize(V_.receptor_types_size_); + P_.receptor_types_.resize(P_.num_of_receptors_); + for (size_t i=0; i < P_.num_of_receptors_; i++) + { + P_.receptor_types_[i] = i+1; } - V_.P11_syn_.resize(V_.receptor_types_size_); - V_.P21_syn_.resize(V_.receptor_types_size_); - V_.P22_syn_.resize(V_.receptor_types_size_); - V_.P31_syn_.resize(V_.receptor_types_size_); - V_.P32_syn_.resize(V_.receptor_types_size_); + V_.P11_syn_.resize(P_.num_of_receptors_); + V_.P21_syn_.resize(P_.num_of_receptors_); + V_.P22_syn_.resize(P_.num_of_receptors_); + V_.P31_syn_.resize(P_.num_of_receptors_); + V_.P32_syn_.resize(P_.num_of_receptors_); - S_.y1_syn_.resize(V_.receptor_types_size_); - S_.y2_syn_.resize(V_.receptor_types_size_); + S_.y1_syn_.resize(P_.num_of_receptors_); + S_.y2_syn_.resize(P_.num_of_receptors_); - V_.PSCInitialValues_.resize(V_.receptor_types_size_); + V_.PSCInitialValues_.resize(P_.num_of_receptors_); - B_.spikes_.resize(V_.receptor_types_size_); + B_.spikes_.resize(P_.num_of_receptors_); V_.P33_ = std::exp(-h/P_.Tau_); V_.P30_ = 1/P_.C_*(1-V_.P33_)*P_.Tau_; - for (unsigned int i=0; i < V_.receptor_types_size_; i++) + for (size_t i=0; i < P_.num_of_receptors_; i++) { V_.P11_syn_[i] = V_.P22_syn_[i] =std::exp(-h/P_.tau_syn_[i]); V_.P21_syn_[i] = h*V_.P11_syn_[i]; @@ -289,7 +281,7 @@ void iaf_psc_alpha_multisynapse::update(Time const& origin, const long_t from, c S_.y3_ = V_.P30_*(S_.y0_ + P_.I_e_) + V_.P33_*S_.y3_; S_.current_=0.0; - for (unsigned int i=0; i < V_.receptor_types_size_; i++){ + for (size_t i=0; i < P_.num_of_receptors_; i++){ S_.y3_ += V_.P31_syn_[i]*S_.y1_syn_[i] + V_.P32_syn_[i]*S_.y2_syn_[i]; S_.current_ += S_.y2_syn_[i]; } @@ -300,7 +292,7 @@ void iaf_psc_alpha_multisynapse::update(Time const& origin, const long_t from, c else // neuron is absolute refractory --S_.r_; - for (unsigned int i=0; i < V_.receptor_types_size_; i++) + for (size_t i=0; i < P_.num_of_receptors_; i++) { // alpha shape PSCs S_.y2_syn_[i] = V_.P21_syn_[i] * S_.y1_syn_[i] + V_.P22_syn_[i] * S_.y2_syn_[i]; @@ -333,40 +325,10 @@ void iaf_psc_alpha_multisynapse::update(Time const& origin, const long_t from, c port iaf_psc_alpha_multisynapse::connect_sender(SpikeEvent&, port receptor_type) { - bool new_rp = true; - - // look if new port is encountered - for(std::vector::const_iterator pii = P_.receptor_types_.begin(); pii != P_.receptor_types_.end(); ++pii) - { - if (*pii == receptor_type) - { - new_rp = false; - break; - } - } - - if (new_rp) - { - - if (P_.num_of_receptors_ <= P_.receptor_types_.size()) - { - // space has not been pre-allocated - ++P_.num_of_receptors_; + if (receptor_type <= 0 || receptor_type > static_cast (P_.num_of_receptors_)) + throw IncompatibleReceptorType(receptor_type, get_name(), "SpikeEvent"); - RingBuffer spiketmp; - spiketmp.clear(); - B_.spikes_.push_back(spiketmp); - - P_.tau_syn_.push_back(2.0); - - V_.PSCInitialValues_.push_back(0.0); - S_.y1_syn_.push_back(0.0); - S_.y2_syn_.push_back(0.0); - } - - P_.receptor_types_.push_back(receptor_type); - V_.receptor_types_size_ = P_.receptor_types_.size(); - } + P_.has_connections_ = true; return receptor_type; } @@ -374,7 +336,7 @@ void iaf_psc_alpha_multisynapse::handle(SpikeEvent& e) { assert(e.get_delay() > 0); - for (unsigned int i=0; i < V_.receptor_types_size_; ++i) + for (size_t i=0; i < P_.num_of_receptors_; ++i) { if (P_.receptor_types_[i] == e.get_rport()){ B_.spikes_[i].add_value(e.get_rel_delivery_steps(network()->get_slice_origin()), diff --git a/models/iaf_psc_alpha_multisynapse.h b/models/iaf_psc_alpha_multisynapse.h index c21c24379c..a5eb1a5fa3 100644 --- a/models/iaf_psc_alpha_multisynapse.h +++ b/models/iaf_psc_alpha_multisynapse.h @@ -138,7 +138,10 @@ namespace nest // type is long because other types are not put through in GetStatus std::vector receptor_types_; - unsigned int num_of_receptors_; + size_t num_of_receptors_; + + // boolean flag which indicates whether the neuron has connections + bool has_connections_; Parameters_(); //!< Sets default parameter values diff --git a/models/iaf_psc_delta.cpp b/models/iaf_psc_delta.cpp index f0c390db17..92ba1d75fb 100644 --- a/models/iaf_psc_delta.cpp +++ b/models/iaf_psc_delta.cpp @@ -314,7 +314,7 @@ void nest::iaf_psc_delta::handle(CurrentEvent& e) // add weighted current; HEP 2002-10-04 B_.currents_.add_value(e.get_rel_delivery_steps(network()->get_slice_origin()), - w *c); + w *c); } void nest::iaf_psc_delta::handle(DataLoggingRequest &e) diff --git a/models/iaf_psc_delta.h b/models/iaf_psc_delta.h index 48632b2df9..5ebacde6a1 100644 --- a/models/iaf_psc_delta.h +++ b/models/iaf_psc_delta.h @@ -130,8 +130,6 @@ namespace nest{ public: - typedef Node base; - iaf_psc_delta(); iaf_psc_delta(const iaf_psc_delta&); diff --git a/models/iaf_psc_exp.cpp b/models/iaf_psc_exp.cpp index 4353afa0a2..5ef5fc9b15 100644 --- a/models/iaf_psc_exp.cpp +++ b/models/iaf_psc_exp.cpp @@ -47,6 +47,10 @@ namespace nest { // use standard names whereever you can for consistency! insert_(names::V_m, &iaf_psc_exp::get_V_m_); + insert_(names::weighted_spikes_ex, &iaf_psc_exp::get_weighted_spikes_ex_); + insert_(names::weighted_spikes_in, &iaf_psc_exp::get_weighted_spikes_in_); + insert_(names::input_currents_ex, &iaf_psc_exp::get_input_currents_ex_); + insert_(names::input_currents_in, &iaf_psc_exp::get_input_currents_in_); } } @@ -267,8 +271,12 @@ void nest::iaf_psc_exp::update(const Time &origin, const long_t from, const long S_.i_syn_in_ *= V_.P11in_; // the spikes arriving at T+1 have an immediate effect on the state of the neuron - S_.i_syn_ex_ += B_.spikes_ex_.get_value(lag); - S_.i_syn_in_ += B_.spikes_in_.get_value(lag); + + V_.weighted_spikes_ex_ = B_.spikes_ex_.get_value(lag); + V_.weighted_spikes_in_ = B_.spikes_in_.get_value(lag); + + S_.i_syn_ex_ += V_.weighted_spikes_ex_; + S_.i_syn_in_ += V_.weighted_spikes_in_; if ( S_.V_m_ >= P_.Theta_ ) // threshold crossing { diff --git a/models/iaf_psc_exp.h b/models/iaf_psc_exp.h index 4a595bb747..72921ee144 100644 --- a/models/iaf_psc_exp.h +++ b/models/iaf_psc_exp.h @@ -122,8 +122,6 @@ namespace nest public: - typedef Node base; - iaf_psc_exp(); iaf_psc_exp(const iaf_psc_exp&); @@ -277,6 +275,9 @@ namespace nest double_t P21ex_; double_t P21in_; double_t P22_; + + double_t weighted_spikes_ex_; + double_t weighted_spikes_in_; int_t RefractoryCounts_; }; @@ -285,6 +286,11 @@ namespace nest //! Read out the real membrane potential double_t get_V_m_() const { return S_.V_m_ + P_.U0_; } + + double_t get_weighted_spikes_ex_() const { return V_.weighted_spikes_ex_; } + double_t get_weighted_spikes_in_() const { return V_.weighted_spikes_in_; } + double_t get_input_currents_ex_() const { return S_.i_syn_ex_; } + double_t get_input_currents_in_() const { return S_.i_syn_in_; } // ---------------------------------------------------------------- diff --git a/models/iaf_psc_exp_multisynapse.cpp b/models/iaf_psc_exp_multisynapse.cpp index 15d0d6aeb4..29235c38ac 100644 --- a/models/iaf_psc_exp_multisynapse.cpp +++ b/models/iaf_psc_exp_multisynapse.cpp @@ -55,16 +55,15 @@ namespace nest * ---------------------------------------------------------------- */ iaf_psc_exp_multisynapse::Parameters_::Parameters_() - : Tau_ ( 10.0 ), // in ms - C_ ( 250.0 ), // in pF - t_ref_ ( 2.0 ), // in ms - U0_ ( -70.0 ), // in mV - I_e_ ( 0.0 ), // in pA - V_reset_ ( -70.0 - U0_ ), // in mV - Theta_ ( -55.0 - U0_ ), // relative U0_ - num_of_receptors_ (0) + : Tau_ ( 10.0 ), // in ms + C_ ( 250.0 ), // in pF + t_ref_ ( 2.0 ), // in ms + U0_ ( -70.0 ), // in mV + I_e_ ( 0.0 ), // in pA + V_reset_ ( -70.0 - U0_ ), // in mV + Theta_ ( -55.0 - U0_ ), // relative U0_ + has_connections_ ( false ) { - receptor_types_.clear(); tau_syn_.clear(); } @@ -90,11 +89,11 @@ void iaf_psc_exp_multisynapse::Parameters_::get(DictionaryDatum &d) const def(d, names::tau_m, Tau_); def(d, names::t_ref, t_ref_); def(d,"n_synapses", num_of_receptors_); + def(d, names::has_connections, has_connections_); ArrayDatum tau_syn_ad(tau_syn_); def(d,"tau_syn", tau_syn_ad); - - (*d)["receptor_types"] = IntVectorDatum(new std::vector(receptor_types_)); + } double iaf_psc_exp_multisynapse::Parameters_::set(const DictionaryDatum& d) @@ -125,17 +124,13 @@ double iaf_psc_exp_multisynapse::Parameters_::set(const DictionaryDatum& d) if ( Tau_ <= 0. ) throw BadProperty("Membrane time constant must be > 0."); - if (updateValue(d, "n_synapses", num_of_receptors_)) - tau_syn_.resize(num_of_receptors_, 2.0); - std::vector tau_tmp; if (updateValue >(d, "tau_syn", tau_tmp)) { - if (tau_tmp.size() != num_of_receptors_) - throw DimensionMismatch(num_of_receptors_, tau_tmp.size()); - for (size_t i = 0; i < tau_tmp.size(); ++i) { + if (tau_tmp.size() < tau_syn_.size() && has_connections_ == true) + throw BadProperty("The neuron has connections, therefore the number of ports cannot be reduced."); if (tau_tmp[i] <= 0) throw BadProperty("All synaptic time constants must be > 0."); if (tau_tmp[i] == Tau_) @@ -143,6 +138,7 @@ double iaf_psc_exp_multisynapse::Parameters_::set(const DictionaryDatum& d) } tau_syn_ = tau_tmp; + num_of_receptors_ = tau_syn_.size(); } if ( t_ref_ < 0. ) @@ -151,8 +147,6 @@ double iaf_psc_exp_multisynapse::Parameters_::set(const DictionaryDatum& d) if ( V_reset_ >= Theta_ ) throw BadProperty("Reset potential must be smaller than threshold."); - updateValue >(d, "receptor_types", receptor_types_); - return delta_EL; } @@ -223,25 +217,23 @@ void nest::iaf_psc_exp_multisynapse::calibrate() const double h = Time::get_resolution().get_ms(); - V_.receptor_types_size_ = P_.receptor_types_.size(); - - // if n_synapses has been Decreased with SetStatus, force new dimension. - if (P_.num_of_receptors_ < V_.receptor_types_size_){ - V_.receptor_types_size_ = P_.num_of_receptors_; - P_.receptor_types_.resize(V_.receptor_types_size_); + P_.receptor_types_.resize(P_.num_of_receptors_); + for (size_t i=0; i < P_.num_of_receptors_; i++) + { + P_.receptor_types_[i] = i+1; } - V_.P11_syn_.resize(V_.receptor_types_size_); - V_.P21_syn_.resize(V_.receptor_types_size_); + V_.P11_syn_.resize(P_.num_of_receptors_); + V_.P21_syn_.resize(P_.num_of_receptors_); - S_.i_syn_.resize(V_.receptor_types_size_); + S_.i_syn_.resize(P_.num_of_receptors_); - B_.spikes_.resize(V_.receptor_types_size_); + B_.spikes_.resize(P_.num_of_receptors_); V_.P22_ = std::exp(-h/P_.Tau_); V_.P20_ = P_.Tau_/P_.C_*(1.0 - V_.P22_); - for (unsigned int i=0; i < V_.receptor_types_size_; i++) + for (size_t i=0; i < P_.num_of_receptors_; i++) { V_.P11_syn_[i] = std::exp(-h/P_.tau_syn_[i]); V_.P21_syn_[i] = P_.Tau_/(P_.C_*(1.0-P_.Tau_/P_.tau_syn_[i])) * V_.P11_syn_[i] * (1.0 - std::exp(h*(1.0/P_.tau_syn_[i]-1.0/P_.Tau_))); @@ -268,7 +260,7 @@ void iaf_psc_exp_multisynapse::update(const Time& origin, const long_t from, con S_.V_m_ = S_.V_m_*V_.P22_ + (P_.I_e_+S_.i_0_)*V_.P20_; // not sure about this S_.current_=0.0; - for (unsigned int i=0; i < V_.receptor_types_size_; i++){ + for (size_t i=0; i < P_.num_of_receptors_; i++){ S_.V_m_ += V_.P21_syn_[i]*S_.i_syn_[i]; S_.current_ += S_.i_syn_[i]; // not sure about this } @@ -276,7 +268,7 @@ void iaf_psc_exp_multisynapse::update(const Time& origin, const long_t from, con else --S_.r_ref_; // neuron is absolute refractory - for (unsigned int i=0; i < V_.receptor_types_size_; i++) + for (size_t i=0; i < P_.num_of_receptors_; i++) { // exponential decaying PSCs S_.i_syn_[i] *= V_.P11_syn_[i]; @@ -305,38 +297,11 @@ void iaf_psc_exp_multisynapse::update(const Time& origin, const long_t from, con port iaf_psc_exp_multisynapse::connect_sender(SpikeEvent&, port receptor_type) { - bool new_rp = true; - - // look if new port is encountered - for(std::vector::const_iterator pii = P_.receptor_types_.begin(); pii != P_.receptor_types_.end(); ++pii) - { - if (*pii == receptor_type) - { - new_rp = false; - break; - } - } - - if (new_rp) - { - - if (P_.num_of_receptors_ <= P_.receptor_types_.size()) - { - // space has not been pre-allocated - ++P_.num_of_receptors_; - - RingBuffer spiketmp; - spiketmp.clear(); - B_.spikes_.push_back(spiketmp); + if (receptor_type <= 0 || receptor_type > static_cast (P_.num_of_receptors_)) + throw IncompatibleReceptorType(receptor_type, get_name(), "SpikeEvent"); - P_.tau_syn_.push_back(2.0); + P_.has_connections_ = true; - S_.i_syn_.push_back(0.0); - } - - P_.receptor_types_.push_back(receptor_type); - V_.receptor_types_size_ = P_.receptor_types_.size(); - } return receptor_type; } @@ -344,7 +309,7 @@ void iaf_psc_exp_multisynapse::handle(SpikeEvent& e) { assert(e.get_delay() > 0); - for (unsigned int i=0; i < V_.receptor_types_size_; ++i) + for (size_t i=0; i < P_.num_of_receptors_; ++i) { if (P_.receptor_types_[i] == e.get_rport()){ B_.spikes_[i].add_value(e.get_rel_delivery_steps(network()->get_slice_origin()), diff --git a/models/iaf_psc_exp_multisynapse.h b/models/iaf_psc_exp_multisynapse.h index 8e2a482825..00bde76a02 100644 --- a/models/iaf_psc_exp_multisynapse.h +++ b/models/iaf_psc_exp_multisynapse.h @@ -108,13 +108,15 @@ namespace nest I.e. the real threshold is (U0_+Theta_). */ double_t Theta_; - /** Time constants of synaptic currents in ms. */ std::vector tau_syn_; // type is long because other types are not put through in GetStatus std::vector receptor_types_; - unsigned int num_of_receptors_; + size_t num_of_receptors_; + + // boolean flag which indicates whether the neuron has connections + bool has_connections_; Parameters_(); //!< Sets default parameter values diff --git a/models/iaf_tum_2000.h b/models/iaf_tum_2000.h index 58c4407bde..4bf1299470 100644 --- a/models/iaf_tum_2000.h +++ b/models/iaf_tum_2000.h @@ -133,8 +133,6 @@ namespace nest public: - typedef Node base; - iaf_tum_2000(); iaf_tum_2000(const iaf_tum_2000&); diff --git a/models/izhikevich.cpp b/models/izhikevich.cpp index 25fde20b9b..95ae9a4fd7 100644 --- a/models/izhikevich.cpp +++ b/models/izhikevich.cpp @@ -47,6 +47,7 @@ namespace nest { // use standard names whereever you can for consistency! insert_(names::V_m, &izhikevich::get_V_m_); + insert_(names::U_m, &izhikevich::get_U_m_); } } diff --git a/models/izhikevich.h b/models/izhikevich.h index 2fa7bb59e4..bbb3d8f584 100644 --- a/models/izhikevich.h +++ b/models/izhikevich.h @@ -213,6 +213,8 @@ namespace nest //! Read out the membrane potential double_t get_V_m_() const { return S_.v_; } + //! Read out the recovery variable + double_t get_U_m_() const { return S_.u_; } // ---------------------------------------------------------------- diff --git a/models/mat2_psc_exp.h b/models/mat2_psc_exp.h index ccf75ba9bb..d731eb4a8a 100644 --- a/models/mat2_psc_exp.h +++ b/models/mat2_psc_exp.h @@ -131,8 +131,6 @@ namespace nest public: - typedef Node base; - mat2_psc_exp(); mat2_psc_exp(const mat2_psc_exp&); diff --git a/models/mcculloch_pitts_neuron.h b/models/mcculloch_pitts_neuron.h index b8ace9f0b2..f1a5bad11b 100644 --- a/models/mcculloch_pitts_neuron.h +++ b/models/mcculloch_pitts_neuron.h @@ -61,6 +61,8 @@ namespace nest only sends a spike if a transition of its state occurs. If the state makes an up-transition it sends a spike with multiplicity 2, if a down transition occurs, it sends a spike with multiplicity 1. + The neuron accepts several sources of currents, e.g. from a + noise_generator. Parameters: tau_m double - Membrane time constant (mean inter-update-interval) in ms. diff --git a/models/mip_generator.cpp b/models/mip_generator.cpp index c4363746a9..d9972361f8 100644 --- a/models/mip_generator.cpp +++ b/models/mip_generator.cpp @@ -136,7 +136,7 @@ void nest::mip_generator::update(Time const & T, const long_t from, const long_t return; // no spikes to be generated // generate spikes of mother process for each time slice - ulong_t n_mother_spikes = V_.poisson_dev_.uldev(P_.rng_); + long_t n_mother_spikes = V_.poisson_dev_.ldev(P_.rng_); if ( n_mother_spikes ) { diff --git a/models/modelsmodule.cpp b/models/modelsmodule.cpp index 9d5c1ae296..1c2f0abb04 100644 --- a/models/modelsmodule.cpp +++ b/models/modelsmodule.cpp @@ -43,10 +43,14 @@ // Neuron models #include "aeif_cond_alpha.h" +#include "aeif_cond_alpha_RK5.h" +#include "aeif_cond_alpha_multisynapse.h" #include "aeif_cond_exp.h" #include "hh_cond_exp_traub.h" #include "hh_psc_alpha.h" #include "ht_neuron.h" +#include "iaf_chs_2007.h" +#include "iaf_chxk_2008.h" #include "iaf_cond_alpha.h" #include "iaf_cond_alpha_mc.h" #include "iaf_cond_exp.h" @@ -61,6 +65,7 @@ #include "mat2_psc_exp.h" #include "parrot_neuron.h" #include "pp_psc_delta.h" +#include "pp_pop_psc_delta.h" #include "sli_neuron.h" #include "ginzburg_neuron.h" #include "mcculloch_pitts_neuron.h" @@ -85,8 +90,8 @@ #include "spin_detector.h" #include "multimeter.h" #include "correlation_detector.h" +#include "correlomatrix_detector.h" -// #include "volume_transmitter.h" @@ -102,6 +107,7 @@ #include "cont_delay_connection.h" #include "tsodyks_connection.h" #include "tsodyks2_connection.h" +#include "quantal_stp_connection.h" #include "stdp_connection.h" #include "stdp_connection_hom.h" #include "stdp_connection_facetshw_hom.h" @@ -134,8 +140,7 @@ namespace nest const std::string ModelsModule::commandstring(void) const { - return std::string("/models-init /C++ ($Revision: 9031 $) provide-component " - "/models-init /SLI ($Revision: 9031 $) require-component"); + return std::string("(models-init) run"); } //------------------------------------------------------------------------------------- @@ -143,6 +148,7 @@ namespace nest void ModelsModule::init(SLIInterpreter *) { register_model(net_, "iaf_neuron"); + register_model(net_, "iaf_chs_2007"); register_model(net_, "iaf_psc_alpha"); register_model(net_, "iaf_psc_alpha_multisynapse"); register_model(net_, "iaf_psc_delta"); @@ -152,6 +158,7 @@ namespace nest register_model(net_, "mat2_psc_exp"); register_model(net_, "parrot_neuron"); register_model(net_, "pp_psc_delta"); + register_model(net_, "pp_pop_psc_delta"); register_model(net_, "ac_generator"); register_model(net_, "dc_generator"); @@ -173,6 +180,7 @@ namespace nest register_model(net_, "spin_detector"); register_model(net_, "multimeter"); register_model(net_, "correlation_detector"); + register_model(net_, "correlomatrix_detector"); register_model(net_, "volume_transmitter"); // Create voltmeter as a multimeter pre-configured to record V_m. @@ -183,6 +191,7 @@ namespace nest register_preconf_model(net_, "voltmeter", vmdict); #ifdef HAVE_GSL + register_model(net_, "iaf_chxk_2008"); register_model(net_, "iaf_cond_alpha"); register_model(net_, "iaf_cond_exp"); register_model(net_, "iaf_cond_exp_sfa_rr"); @@ -197,6 +206,9 @@ namespace nest register_model(net_, "aeif_cond_exp"); register_model(net_, "ht_neuron"); #endif + // This version of the AdEx model does not depend on GSL. + register_model(net_, "aeif_cond_alpha_RK5"); + register_model(net_, "aeif_cond_alpha_multisynapse"); #ifdef HAVE_MUSIC //// proxies for inter-application communication using MUSIC @@ -221,6 +233,7 @@ namespace nest register_prototype_connection(net_, "tsodyks2_synapse"); register_prototype_connection(net_, "stdp_synapse"); register_prototype_connection(net_, "ht_synapse"); + register_prototype_connection< Quantal_StpConnection>(net_, "quantal_stp_synapse"); register_prototype_connection_commonproperties < STDPConnectionHom, STDPHomCommonProperties diff --git a/models/modelsmodule.h b/models/modelsmodule.h index ac343732a2..96a9cec1d4 100644 --- a/models/modelsmodule.h +++ b/models/modelsmodule.h @@ -22,20 +22,6 @@ #ifndef MODELSMODULE_H #define MODELSMODULE_H -/* - This file is part of NEST - - modelmodule.h -- Header to the modelmodule - (see cpp file for details) - - - Author: Marc-Oliver Gewaltig (marc-oliver.gewaltig@honda-ri.de) - Hans Ekkehard Plesser (hans.ekkehard.plesser@umb.no) - - $Date: 2012-11-15 17:09:23 +0100 (Thu, 15 Nov 2012) $ - Last change: $Author: eppler $ - $Revision: 9952 $ -*/ #include "slimodule.h" diff --git a/models/music_event_out_proxy.cpp b/models/music_event_out_proxy.cpp index 026c1fb471..53590252e9 100644 --- a/models/music_event_out_proxy.cpp +++ b/models/music_event_out_proxy.cpp @@ -191,8 +191,15 @@ void nest::music_event_out_proxy::handle(SpikeEvent & e) double_t time = e.get_stamp().get_ms()*1e-3; // event time in seconds long_t receiver_port = e.get_rport(); - for (int_t i = 0; i < e.get_multiplicity(); ++i) - V_.MP_->insertEvent(time, MUSIC::GlobalIndex(receiver_port)); +#ifdef _OPENMP +#pragma omp critical (insertevent) + { +#endif + for (int_t i = 0; i < e.get_multiplicity(); ++i) + V_.MP_->insertEvent(time, MUSIC::GlobalIndex(receiver_port)); +#ifdef _OPENMP + } +#endif } #endif diff --git a/models/noise_generator.cpp b/models/noise_generator.cpp index 9cf9ff41b7..9f97a3b406 100644 --- a/models/noise_generator.cpp +++ b/models/noise_generator.cpp @@ -26,6 +26,7 @@ #include "integerdatum.h" #include "doubledatum.h" #include "dictutils.h" +#include "numerics.h" /* ---------------------------------------------------------------- * Default constructors defining default parameter @@ -34,13 +35,24 @@ nest::noise_generator::Parameters_::Parameters_() : mean_(0.0), // pA std_(0.0), // pA / sqrt(s) + std_mod_(0.0), // pA / sqrt(s) + freq_ (0.0), // Hz + phi_deg_(0.0), // degree dt_(Time::ms(1.0)), num_targets_(0) {} +nest::noise_generator::State_::State_() + : y_0_ (0.0), + y_1_ (0.0) // pA +{} + nest::noise_generator::Parameters_::Parameters_(const Parameters_& p) : mean_(p.mean_), std_(p.std_), + std_mod_(p.std_mod_), + freq_ (p.freq_), + phi_deg_(p.phi_deg_), dt_(p.dt_), num_targets_(0) // we do not copy connections { @@ -58,20 +70,38 @@ void nest::noise_generator::Parameters_::get(DictionaryDatum &d) const { (*d)[names::mean] = mean_; (*d)[names::std ] = std_; + (*d)[names::std_mod ] = std_mod_; (*d)[names::dt] = dt_.get_ms(); + (*d)[names::phase ] = phi_deg_; + (*d)[names::frequency] = freq_; } +void nest::noise_generator::State_::get(DictionaryDatum &d) const +{ + (*d)["y_0"] = y_0_; + (*d)["y_1"] = y_1_; +} + void nest::noise_generator::Parameters_::set(const DictionaryDatum& d, const noise_generator& n) { updateValue(d, names::mean, mean_); updateValue(d, names::std , std_); + updateValue(d, names::std_mod , std_mod_); + updateValue(d, names::frequency, freq_); + updateValue(d, names::phase , phi_deg_); double_t dt; if ( updateValue(d, names::dt, dt) ) dt_ = Time::ms(dt); if ( std_ < 0 ) throw BadProperty("The standard deviation cannot be negative."); + + if ( std_mod_ < 0 ) + throw BadProperty("The standard deviation cannot be negative."); + + if ( std_mod_ > std_ ) + throw BadProperty("The modulation apmlitude must be smaller or equal to the baseline amplitude."); if ( !dt_.is_step() ) throw StepMultipleRequired(n.get_name(), names::dt, dt_); @@ -132,6 +162,23 @@ void nest::noise_generator::calibrate() } V_.dt_steps_ = P_.dt_.get_steps(); + + const double_t h = Time::get_resolution().get_ms(); + const double_t t = network()->get_time().get_ms(); + + // scale Hz to ms + const double_t omega = 2.0 * numerics::pi * P_.freq_ / 1000.0; + const double_t phi_rad = P_.phi_deg_ * 2.0 * numerics::pi / 360.0; + + // initial state + S_.y_0_ = std::cos(omega * t + phi_rad); + S_.y_1_ = std::sin(omega * t + phi_rad); + + // matrix elements + V_.A_00_ = std::cos(omega * h); + V_.A_01_ = -std::sin(omega * h); + V_.A_10_ = std::sin(omega * h); + V_.A_11_ = std::cos(omega * h); } @@ -164,13 +211,22 @@ void nest::noise_generator::update(Time const &origin, const long_t from, const if ( !device_.is_active(Time::step(now)) ) continue; + if ( P_.std_mod_ != 0. ) + { + const double_t y_0 = S_.y_0_; + S_.y_0_ = V_.A_00_ * y_0 + V_.A_01_ * S_.y_1_; + S_.y_1_ = V_.A_10_ * y_0 + V_.A_11_ * S_.y_1_; + } + // >= in case we woke from inactivity if( now >= B_.next_step_ ) { // compute new currents for ( AmpVec_::iterator it = B_.amps_.begin() ; it != B_.amps_.end() ; ++it ) - *it = P_.mean_ + P_.std_ * V_.normal_dev_(net_->get_rng(get_thread())); + { + *it = P_.mean_ + std::sqrt( P_.std_ * P_.std_ + S_.y_1_ * P_.std_mod_ * P_.std_mod_ ) * V_.normal_dev_(net_->get_rng(get_thread())); + } // use now as reference, in case we woke up from inactive period B_.next_step_ = now + V_.dt_steps_; diff --git a/models/noise_generator.h b/models/noise_generator.h index 5ed7795969..e4967e954c 100644 --- a/models/noise_generator.h +++ b/models/noise_generator.h @@ -42,7 +42,8 @@ This device can be used to inject a Gaussian "white" noise current into a node. The current is not really white, but a piecewise constant current with Gaussian distributed amplitude. The current changes at intervals of dt. dt must be a multiple of the simulation step size, the default is 1.0ms, -corresponding to a 1kHz cut-off. +corresponding to a 1kHz cut-off. +Additionally a second sinusodial modulated term can be added to the standard deviation of the noise. The current generated is given by @@ -50,13 +51,19 @@ The current generated is given by where N_j are Gaussian random numbers with unit standard deviation and t_0 is the device onset time. +If the modulation is added the current is given by + + I(t) = mean + sqrt(std^2 + std_mod^2 * sin(omega * t + phase)) * N_j for t_0 + j dt <= t < t_0 + (j-1) dt Parameters: The following parameters can be set in the status dictionary: -mean double - mean value of the noise current in pA -std double - standard deviation of noise current in pA -dt double - interval between changes in current in ms, default 1.0ms +mean double - mean value of the noise current in pA +std double - standard deviation of noise current in pA +dt double - interval between changes in current in ms, default 1.0ms +std_mod double - modulated standard deviation of noise current in pA +phase double - Phase of sine modulation (0-360 deg) +frequency double - Frequency of sine modulation in Hz Remarks: - All targets receive different currents. @@ -136,10 +143,13 @@ Author: Ported to NEST2 API 08/2007 by Jochen Eppler, updated 07/2008 by HEP * Store independent parameters of the model. */ struct Parameters_ { - double_t mean_; //!< mean current, in pA - double_t std_; //!< standard deviation of current, in pA - Time dt_; //!< time interval between updates - + double_t mean_; //!< mean current, in pA + double_t std_; //!< standard deviation of current, in pA + double_t std_mod_; //!< standard deviation of current modulation, in pA + double_t freq_; //!< Standard frequency in Hz + double_t phi_deg_; //!< Phase of sinusodial noise modulation (0-360 deg) + Time dt_; //!< time interval between updates + /** * Number of targets. * This is a hidden parameter; must be placed in parameters, @@ -155,6 +165,17 @@ Author: Ported to NEST2 API 08/2007 by Jochen Eppler, updated 07/2008 by HEP void set(const DictionaryDatum&, const noise_generator&); //!< Set values from dicitonary }; + // ------------------------------------------------------------ + + struct State_ { + double_t y_0_; + double_t y_1_; + + State_(); //!< Sets default parameter values + + void get(DictionaryDatum&) const; //!< Store current values in dictionary + }; + // ------------------------------------------------------------ struct Buffers_ { @@ -167,6 +188,14 @@ Author: Ported to NEST2 API 08/2007 by Jochen Eppler, updated 07/2008 by HEP struct Variables_ { long_t dt_steps_; //!< update interval in steps librandom::NormalRandomDev normal_dev_; //!< random deviate generator + double_t omega_; //!< Angelfrequency i rad/s + double_t phi_rad_; //!< Phase of sine current (0-2Pi rad) + + // The exact integration matrix + double_t A_00_; + double_t A_01_; + double_t A_10_; + double_t A_11_; }; // ------------------------------------------------------------ @@ -175,6 +204,7 @@ Author: Ported to NEST2 API 08/2007 by Jochen Eppler, updated 07/2008 by HEP Parameters_ P_; Variables_ V_; Buffers_ B_; + State_ S_; }; @@ -182,6 +212,7 @@ Author: Ported to NEST2 API 08/2007 by Jochen Eppler, updated 07/2008 by HEP void noise_generator::get_status(DictionaryDatum &d) const { P_.get(d); + S_.get(d); device_.get_status(d); } diff --git a/models/poisson_generator.cpp b/models/poisson_generator.cpp index 091504dd0a..47c8c2f913 100644 --- a/models/poisson_generator.cpp +++ b/models/poisson_generator.cpp @@ -120,7 +120,7 @@ void nest::poisson_generator::update(Time const & T, const long_t from, const lo void nest::poisson_generator::event_hook(DSSpikeEvent& e) { librandom::RngPtr rng = net_->get_rng(get_thread()); - ulong_t n_spikes = V_.poisson_dev_.uldev(rng); + long_t n_spikes = V_.poisson_dev_.ldev(rng); if ( n_spikes > 0 ) // we must not send events with multiplicity 0 { diff --git a/models/pp_pop_psc_delta.cpp b/models/pp_pop_psc_delta.cpp new file mode 100755 index 0000000000..4ed34c8974 --- /dev/null +++ b/models/pp_pop_psc_delta.cpp @@ -0,0 +1,410 @@ +/* + * pp_pop_psc_delta.cpp + * + * This file is part of NEST. + * + * Copyright (C) 2004 The NEST Initiative + * + * NEST 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 2 of the License, or + * (at your option) any later version. + * + * NEST 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 NEST. If not, see . + * + */ + +/* + * Multimeter support by Yury V. Zaytsev. + */ + + +#include "exceptions.h" +#include "pp_pop_psc_delta.h" +#include "network.h" +#include "dict.h" +#include "integerdatum.h" +#include "doubledatum.h" +#include "dictutils.h" +#include "numerics.h" +#include "universal_data_logger_impl.h" + +#include +#include + +namespace nest +{ + /* ---------------------------------------------------------------- + * Recordables map + * ---------------------------------------------------------------- */ + + RecordablesMap pp_pop_psc_delta::recordablesMap_; + + // Override the create() method with one call to RecordablesMap::insert_() + // for each quantity to be recorded. + template <> + void RecordablesMap::create() + { + // use standard names whereever you can for consistency! + insert_(names::V_m, &pp_pop_psc_delta::get_V_m_); + insert_(names::n_events, &pp_pop_psc_delta::get_n_events_); // n_events instead of E_sfa + } + +/* ---------------------------------------------------------------- + * Default constructors defining default parameters and state + * ---------------------------------------------------------------- */ + +nest::pp_pop_psc_delta::Parameters_::Parameters_() + : N_ ( 100 ), + tau_m_ ( 10.0 ), // ms + c_m_ ( 250.0 ), // pF + rho_0_ ( 10.0 ), // 1/s + delta_u_ ( 1.0 ), // mV + len_kernel_ ( 5.0 ), + I_e_ ( 0.0 ) // pA +{ + taus_eta_.push_back(10.0); + vals_eta_.push_back(0.0); +} + +nest::pp_pop_psc_delta::State_::State_() + : y0_ (0.0), + h_ (0.0), + p_age_occupations_ ( 0 ), + p_n_spikes_past_ ( 0 ) +{ + age_occupations_.clear(); + thetas_ages_.clear(); + n_spikes_past_.clear(); + n_spikes_ages_.clear(); + rhos_ages_.clear(); +} + +/* ---------------------------------------------------------------- + * Parameter and state extractions and manipulation functions + * ---------------------------------------------------------------- */ + +void nest::pp_pop_psc_delta::Parameters_::get(DictionaryDatum &d) const +{ + def(d, names::N, N_); + def(d, names::rho_0, rho_0_); + def(d, names::delta_u, delta_u_); + def(d, names::I_e, I_e_); + def(d, names::C_m, c_m_); + def(d, names::tau_m, tau_m_); + def(d, names::len_kernel, len_kernel_); + + ArrayDatum taus_eta_list_ad(taus_eta_); + def(d,names::taus_eta, taus_eta_list_ad); + + ArrayDatum vals_eta_list_ad(vals_eta_); + def(d,names::vals_eta, vals_eta_list_ad); +} + +void nest::pp_pop_psc_delta::Parameters_::set(const DictionaryDatum& d) +{ + + updateValue(d, names::N, N_); + updateValue(d, names::rho_0, rho_0_); + updateValue(d, names::delta_u, delta_u_); + updateValue(d, names::len_kernel, len_kernel_); + + updateValue(d, names::I_e, I_e_); + updateValue(d, names::C_m, c_m_); + updateValue(d, names::tau_m, tau_m_); + updateValue >(d, names::taus_eta, taus_eta_); + updateValue >(d, names::vals_eta, vals_eta_); + + + + if (taus_eta_.size() != vals_eta_.size()) + throw DimensionMismatch(taus_eta_.size(), vals_eta_.size()); + + if ( c_m_ <= 0 ) + throw BadProperty("Capacitance must be strictly positive."); + + if ( tau_m_ <= 0 ) + throw BadProperty("The time constants must be strictly positive."); + + for(uint_t i = 0 ; i < taus_eta_.size() ; i++ ) + { + if ( taus_eta_[i] <= 0 ) + throw BadProperty("All time constants must be strictly positive."); + } + + if ( N_ <= 0) + throw BadProperty("Number of neurons must be positive."); + + if ( rho_0_ < 0) + throw BadProperty("Rho_0 cannot be negative."); + + if ( delta_u_ <= 0) + throw BadProperty("Delta_u must be positive."); + +} + +void nest::pp_pop_psc_delta::State_::get(DictionaryDatum &d, const Parameters_&) const +{ + def(d, names::V_m, h_); // Filterd version of input + int n_spikes = n_spikes_past_.size()>0 ? n_spikes_past_[p_n_spikes_past_] : 0; // return 0 if n_spikes_past_ has not been initialized yet + def(d, names::n_events, n_spikes); // Number of generated spikes +} + +void nest::pp_pop_psc_delta::State_::set(const DictionaryDatum& d, const Parameters_&) +{ + updateValue(d, names::V_m, h_); +} + +nest::pp_pop_psc_delta::Buffers_::Buffers_(pp_pop_psc_delta &n) + : logger_(n) +{} + +nest::pp_pop_psc_delta::Buffers_::Buffers_(const Buffers_ &, pp_pop_psc_delta &n) + : logger_(n) +{} + +/* ---------------------------------------------------------------- + * Default and copy constructor for node + * ---------------------------------------------------------------- */ + +nest::pp_pop_psc_delta::pp_pop_psc_delta() + : Archiving_Node(), + P_(), + S_(), + B_(*this) +{ + recordablesMap_.create(); +} + +nest::pp_pop_psc_delta::pp_pop_psc_delta(const pp_pop_psc_delta& n) + : Archiving_Node(n), + P_(n.P_), + S_(n.S_), + B_(n.B_, *this) +{} + +/* ---------------------------------------------------------------- + * Node initialization functions + * ---------------------------------------------------------------- */ + +void nest::pp_pop_psc_delta::init_state_(const Node& proto) +{ + const pp_pop_psc_delta& pr = downcast(proto); + S_ = pr.S_; +} + +void nest::pp_pop_psc_delta::init_buffers_() +{ + B_.spikes_.clear(); //!< includes resize + B_.currents_.clear(); //!< includes resize + B_.logger_.reset(); //!< includes resize + Archiving_Node::clear_history(); +} + +void nest::pp_pop_psc_delta::calibrate() +{ + + if (P_.taus_eta_.size() == 0) + throw BadProperty("Time constant array should not be empty. "); + + if (P_.vals_eta_.size() == 0) + throw BadProperty("Adaptation value array should not be empty. "); + + B_.logger_.init(); + + V_.h_ = Time::get_resolution().get_ms(); + V_.rng_ = net_->get_rng(get_thread()); + + + V_.P33_ = std::exp(-V_.h_/P_.tau_m_); + V_.P30_ = 1/P_.c_m_*(1-V_.P33_)*P_.tau_m_; + + + double_t tau_eta_max = -1; // finding max of taus_eta_ + for(uint_t j = 0 ; j < P_.taus_eta_.size() ; j++ ) + if (P_.taus_eta_.at(j) > tau_eta_max) + tau_eta_max = P_.taus_eta_.at(j); + + + V_.len_eta_ = tau_eta_max * (P_.len_kernel_ / V_.h_); + + + + for(int_t j = 0 ; j < V_.len_eta_ ; j++) + S_.n_spikes_past_.push_back(0); + + + vector ts; + ts.clear(); + for(int_t j = 0 ; j < V_.len_eta_ ; j++) + ts.push_back(j*V_.h_); + + double_t temp = 0; + + for(int_t j = 0 ; j < V_.len_eta_ ; j++) + { + for(uint_t i = 0 ; i < P_.taus_eta_.size() ; i++) + temp += std::exp(-ts[j]/P_.taus_eta_.at(i))*(-P_.vals_eta_.at(i)); + + V_.theta_kernel_.push_back(temp); + V_.eta_kernel_.push_back(std::exp(temp)-1); + temp = 0; + } + + for(int_t j = 0 ; j < V_.len_eta_ ; j++){ + S_.age_occupations_.push_back(0); + S_.thetas_ages_.push_back(0); + S_.n_spikes_ages_.push_back(0); + S_.rhos_ages_.push_back(0); + } + S_.age_occupations_.push_back(P_.N_); + S_.thetas_ages_.push_back(0); + S_.n_spikes_ages_.push_back(0); + S_.rhos_ages_.push_back(0); + +} + +/* ---------------------------------------------------------------- + * Update and spike handling functions + */ + +void nest::pp_pop_psc_delta::update(Time const & origin, const long_t from, const long_t to) +{ + assert(to >= 0 && (delay) from < Scheduler::get_min_delay()); + assert(from < to); + + for ( long_t lag = from ; lag < to ; ++lag ) + { + + + S_.h_ = S_.h_*V_.P33_ + V_.P30_*(S_.y0_ + P_.I_e_) + B_.spikes_.get_value(lag); + + + //get_thetas_ages + std::vector tmp_vector; + double_t integral = 0; + tmp_vector.clear(); + + + for(uint_t i = 0 ; i < V_.eta_kernel_.size() ; i++){ + tmp_vector.push_back(V_.eta_kernel_[i] * S_.n_spikes_past_[(S_.p_n_spikes_past_ + i) % S_.n_spikes_past_.size()]* V_.h_ * 0.001); + integral += tmp_vector[i]; + } + + S_.thetas_ages_.clear(); + S_.thetas_ages_.push_back(integral); + + for(uint_t i = 1 ; i < V_.eta_kernel_.size() ; i++) + S_.thetas_ages_.push_back(S_.thetas_ages_[i-1] - tmp_vector[i-1]); + + for(uint_t i = 0 ; i < V_.eta_kernel_.size() ; i++) + S_.thetas_ages_[i] += V_.theta_kernel_[i]; + + S_.thetas_ages_.push_back(0); + + // get_escape_rate + for(uint_t i = 0 ; i < S_.rhos_ages_.size() ; i++) + S_.rhos_ages_[i] = P_.rho_0_ * std::exp((S_.h_ + S_.thetas_ages_[i])/P_.delta_u_); + + + double p_argument; + + // generate_spikes + for (uint_t i = 0 ; i < S_.age_occupations_.size() ; i++ ) + { + + if (S_.age_occupations_[(S_.p_age_occupations_ + i) % S_.age_occupations_.size()] > 0) + { + + p_argument = -numerics::expm1(-S_.rhos_ages_[i] * V_.h_ * 0.001); // V_.h_ is in ms, S_.rhos_ages_ is in Hz + + + if ( p_argument <= 0.00000001 ) // check whether p_argument is zero, 0.00000001 is choosed to conquer floating point problem + { + S_.n_spikes_ages_[i] = 0 ; + } + else + { + V_.binom_dev_.set_p_n(p_argument, S_.age_occupations_[(S_.p_age_occupations_ + i) % S_.age_occupations_.size()]); + S_.n_spikes_ages_[i] = V_.binom_dev_.ldev(V_.rng_); + } + } + else + S_.n_spikes_ages_[i] = 0; + } + + + S_.p_n_spikes_past_ = (S_.p_n_spikes_past_ - 1 + S_.n_spikes_past_.size()) % S_.n_spikes_past_.size(); // shift to the right + + int_t temp_sum = 0; + for (uint_t i = 0 ; i < S_.n_spikes_ages_.size() ; i++ ) // cumulative sum + temp_sum += S_.n_spikes_ages_[i]; + + S_.n_spikes_past_[S_.p_n_spikes_past_] = temp_sum; + + + // update_age_occupations + for (uint_t i = 0 ; i < S_.age_occupations_.size() ; i++ ) + S_.age_occupations_[(S_.p_age_occupations_ + i) % S_.age_occupations_.size()] -= S_.n_spikes_ages_[i]; + + int_t last_element_value = S_.age_occupations_[(S_.p_age_occupations_ - 1 + S_.age_occupations_.size()) % S_.age_occupations_.size() ]; // save the last element + + S_.p_age_occupations_ = (S_.p_age_occupations_ - 1 + S_.age_occupations_.size()) % S_.age_occupations_.size(); // shift to the right + S_.age_occupations_[ (S_.p_age_occupations_ - 1 + S_.age_occupations_.size()) % S_.age_occupations_.size() ] += last_element_value; + S_.age_occupations_[ S_.p_age_occupations_ ] = S_.n_spikes_past_[ S_.p_n_spikes_past_ ]; + + // Set new input current + S_.y0_ = B_.currents_.get_value(lag); + + // Voltage logging + B_.logger_.record_data(origin.get_steps() + lag); + + + // test if S_.n_spikes_past_[S_.p_n_spikes_past_]!=0, generate spike and send this number as the parameter + + if(S_.n_spikes_past_[S_.p_n_spikes_past_]>0) // Is there any spike? + { + SpikeEvent se; + se.set_multiplicity(S_.n_spikes_past_[S_.p_n_spikes_past_]); + network()->send(*this, se, lag); + } + + } +} + +void nest::pp_pop_psc_delta::handle(SpikeEvent & e) +{ + assert(e.get_delay() > 0); + + // EX: We must compute the arrival time of the incoming spike + // explicitly, since it depends on delay and offset within + // the update cycle. The way it is done here works, but + // is clumsy and should be improved. + B_.spikes_.add_value(e.get_rel_delivery_steps(network()->get_slice_origin()), + e.get_weight() * e.get_multiplicity() ); +} + +void nest::pp_pop_psc_delta::handle(CurrentEvent& e) +{ + assert(e.get_delay() > 0); + + const double_t c=e.get_current(); + const double_t w=e.get_weight(); + + // Add weighted current; HEP 2002-10-04 + B_.currents_.add_value(e.get_rel_delivery_steps(network()->get_slice_origin()), + w *c); +} + +void nest::pp_pop_psc_delta::handle(DataLoggingRequest &e) +{ + B_.logger_.handle(e); +} + +} // namespace diff --git a/models/pp_pop_psc_delta.h b/models/pp_pop_psc_delta.h new file mode 100755 index 0000000000..7fc56f9a87 --- /dev/null +++ b/models/pp_pop_psc_delta.h @@ -0,0 +1,400 @@ +/* + * pp_pop_psc_delta.h + * + * This file is part of NEST. + * + * Copyright (C) 2004 The NEST Initiative + * + * NEST 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 2 of the License, or + * (at your option) any later version. + * + * NEST 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 NEST. If not, see . + * + */ + +#ifndef PP_POP_PSC_DELTA_H +#define PP_POP_PSC_DELTA_H + +#include "nest.h" +#include "event.h" +#include "archiving_node.h" +#include "ring_buffer.h" +#include "connection.h" +#include "binomial_randomdev.h" +#include "universal_data_logger.h" + + +namespace nest{ + + + class Network; + + /* BeginDocumentation + Name: pp_pop_psc_delta - Population of point process neurons with leaky integration of delta-shaped PSCs. + + Description: + + pp_pop_psc_delta is an effective model of a population of neurons. The + N component neurons are assumed to be spike response models with escape + noise, also known as generalized linear models. We follow closely the + nomenclature of [1]. The component neurons are a special case of + pp_psc_delta (with purely exponential rate function, no reset and no + random dead_time). All neurons in the population share the inputs that it + receives, and the output is the pooled spike train. + + The instantaneous firing rate of the N component neurons is defined as + + rate(t) = rho_0 * exp( (h(t) - eta(t))/delta_u ), + + where h(t) is the input potential (synaptic delta currents convolved with + an exponential kernel with time constant tau_m), eta(t) models the effect + of refractoriness and adaptation (the neuron's own spike train convolved with + a sum of exponential kernels with time constants taus_eta), and delta_u + sets the scale of the voltages. + + To represent a (homogeneous) population of N inhomogeneous renewal process + neurons, we can keep track of the numbers of neurons that fired a certain number + of time steps in the past. These neurons will have the same value of the + hazard function (instantaneous rate), and we draw a binomial random number + for each of these groups. This algorithm is thus very similar to + ppd_sup_generator and gamma_sup_generator, see also [2]. + + However, the adapting threshold eta(t) of the neurons generally makes the neurons + non-renewal processes. We employ the quasi-renewal approximation + [1],.to be able to use the above algorithm. For the extension of [1] to + coupled populations see [3]. + + In effect, in each simulation time step, a binomial random number for each + of the groups of neurons has to be drawn, independent of the number of + represented neurons. For large N, it should be much more efficient than + simulating N individual pp_psc_delta models. + + pp_pop_psc_delta emits spike events like other neuron models, but no more + than one per time step. If several component neurons spike in the time step, + the multiplicity of the spike event is set accordingly. Thus, to monitor + its output, the mulitplicity of the spike events has to be taken into account. + Alternatively, the internal variable n_events gives the number of spikes + emitted in a time step, and can be monitored using a multimeter. + + A journal article that describes the model and algorithm in detail is + currently in preparation. + + + References: + + [1] Naud R, Gerstner W (2012) Coding and decoding with adapting neurons: + a population approach to the peri-stimulus time histogram. + PLoS Comput Biol 8: e1002711. + + [2] Deger M, Helias M, Boucsein C, Rotter S (2012) Statistical properties + of superimposed stationary spike trains. Journal of Computational + Neuroscience 32:3, 443-463. + + [3] Deger M, Schwalger T, Naud R, Gerstner W (2013) Dynamics of interacting + finite-sized networks of spiking neurons with adaptation. arXiv 1311.4206. + + + + Parameters: + + The following parameters can be set in the status dictionary. + + + N int - Number of represented neurons. + tau_m double - Membrane time constant in ms. + C_m double - Specific capacitance of the membrane in pF/mum^2. + rho_0 double - Base firing rate in 1/s. + delta_u double - Voltage scale parameter in mV. + I_e double - Constant input current in pA. + taus_eta list of doubles - time constants of post-spike kernel in ms. + vals_eta list of doubles - amplitudes of exponentials in post-spike-kernel in mV. + len_kernel double - post-spike kernel eta is truncated after max(taus_eta) * len_kernel. + + + The parameters correspond to the ones of pp_psc_delta as follows. + + c_1 = 0.0 + c_2 = rho_0 + c_3 = 1/delta_u + q_sfa = vals_eta + tau_sfa = taus_eta + I_e = I_e + + dead_time = simulation resolution + dead_time_random = False + with_reset = False + t_ref_remaining = 0.0 + + + Sends: SpikeEvent + + Receives: SpikeEvent, CurrentEvent, DataLoggingRequest + + Author: May 2014, Setareh, Deger + SeeAlso: pp_psc_delta, ppd_sup_generator, gamma_sup_generator + */ + + /** + * Population of point process neurons with leaky integration of delta-shaped PSCs. + */ + + + + class pp_pop_psc_delta: + public Archiving_Node + { + + public: + + pp_pop_psc_delta(); + pp_pop_psc_delta(const pp_pop_psc_delta&); + + /** + * Import sets of overloaded virtual functions. + * We need to explicitly include sets of overloaded + * virtual functions into the current scope. + * According to the SUN C++ FAQ, this is the correct + * way of doing things, although all other compilers + * happily live without. + */ + + using Node::connect_sender; + using Node::handle; + + port check_connection(Connection&, port); + + void handle(SpikeEvent &); + void handle(CurrentEvent &); + void handle(DataLoggingRequest &); + + port connect_sender(SpikeEvent &, port); + port connect_sender(CurrentEvent &, port); + port connect_sender(DataLoggingRequest &, port); + + void get_status(DictionaryDatum &) const; + void set_status(const DictionaryDatum &); + + private: + + void init_state_(const Node& proto); + void init_buffers_(); + void calibrate(); + + void update(Time const &, const long_t, const long_t); + + // The next two classes need to be friends to access the State_ class/member + friend class RecordablesMap; + friend class UniversalDataLogger; + + // ---------------------------------------------------------------- + + /** + * Independent parameters of the model. + */ + struct Parameters_ { + + /** Number of neurons in the population. */ + int_t N_; // by Hesam + + /** Membrane time constant in ms. */ + double_t tau_m_; + + /** Membrane capacitance in pF. */ + double_t c_m_; + + /** ------------ */ + double_t rho_0_; + + /** ------------ */ + double_t delta_u_; + + /** Length of kernel */ + int_t len_kernel_; + + /** External DC current. */ + double_t I_e_; + + /** Array of time constants */ + std::vector taus_eta_; + + /** -------------- */ + std::vector vals_eta_; + + Parameters_(); //!< Sets default parameter values + void get(DictionaryDatum&) const; //!< Store current values in dictionary + void set(const DictionaryDatum&); //!< Set values from dictionary + }; + + // ---------------------------------------------------------------- + + /** + * State variables of the model. + */ + struct State_ { + + double_t y0_; + + double_t h_; + + std::vector age_occupations_; + std::vector thetas_ages_; + std::vector n_spikes_past_; + std::vector n_spikes_ages_; + std::vector rhos_ages_; + + // ring array pointers + int_t p_age_occupations_; + int_t p_n_spikes_past_; + + State_(); //!< Default initialization + + void get(DictionaryDatum&, const Parameters_&) const; + void set(const DictionaryDatum&, const Parameters_&); + }; + + // ---------------------------------------------------------------- + + /** + * Buffers of the model. + */ + struct Buffers_ { + Buffers_(pp_pop_psc_delta &); + Buffers_(const Buffers_ &, pp_pop_psc_delta &); + + /** buffers and sums up incoming spikes/currents */ + RingBuffer spikes_; + RingBuffer currents_; + + //! Logger for all analog data + UniversalDataLogger logger_; + }; + + // ---------------------------------------------------------------- + + /** + * Internal variables of the model. + */ + struct Variables_ { + + + double_t P30_; + double_t P33_; + + int_t len_eta_; + std::vector theta_kernel_; + std::vector eta_kernel_; + + double_t h_; //!< simulation time step in ms + + + + + librandom::RngPtr rng_; // random number generator of my own thread + + librandom::BinomialRandomDev binom_dev_; // binomial random generator + + + int_t DeadTimeCounts_; + + }; + + // Access functions for UniversalDataLogger ----------------------- + + //! Read out the real membrane potential + double_t get_V_m_() const { return S_.h_; } // filtered input + + //! Read out the adaptive threshold potential + double_t get_n_events_() const { return S_.n_spikes_past_[S_.p_n_spikes_past_]; } // number of generated spikes + + // ---------------------------------------------------------------- + + /** + * @defgroup iaf_psc_alpha_data + * Instances of private data structures for the different types + * of data pertaining to the model. + * @note The order of definitions is important for speed. + * @{ + */ + Parameters_ P_; + State_ S_; + Variables_ V_; + Buffers_ B_; + /** @} */ + + //! Mapping of recordables names to access functions + static RecordablesMap recordablesMap_; + }; + + inline + port pp_pop_psc_delta::check_connection(Connection& c, port receptor_type) + { + SpikeEvent e; + e.set_sender(*this); + c.check_event(e); + return c.get_target()->connect_sender(e, receptor_type); + } + + inline + port pp_pop_psc_delta::connect_sender(SpikeEvent&, port receptor_type) + { + if (receptor_type != 0) + throw UnknownReceptorType(receptor_type, get_name()); + return 0; + } + + inline + port pp_pop_psc_delta::connect_sender(CurrentEvent&, port receptor_type) + { + if (receptor_type != 0) + throw UnknownReceptorType(receptor_type, get_name()); + return 0; + } + + inline + port pp_pop_psc_delta::connect_sender(DataLoggingRequest &dlr, + port receptor_type) + { + if (receptor_type != 0) + throw UnknownReceptorType(receptor_type, get_name()); + return B_.logger_.connect_logging_device(dlr, recordablesMap_); + } + +inline +void pp_pop_psc_delta::get_status(DictionaryDatum &d) const +{ + P_.get(d); + S_.get(d, P_); + Archiving_Node::get_status(d); + (*d)[names::recordables] = recordablesMap_.get_list(); +} + +inline +void pp_pop_psc_delta::set_status(const DictionaryDatum &d) +{ + Parameters_ ptmp = P_; // temporary copy in case of errors + ptmp.set(d); // throws if BadProperty + State_ stmp = S_; // temporary copy in case of errors + stmp.set(d, ptmp); // throws if BadProperty + + // We now know that (ptmp, stmp) are consistent. We do not + // write them back to (P_, S_) before we are also sure that + // the properties to be set in the parent class are internally + // consistent. + Archiving_Node::set_status(d); + + // if we get here, temporaries contain consistent set of properties + P_ = ptmp; + S_ = stmp; +} + +} // namespace + +#endif /* #ifndef PP_POP_PSC_DELTA_H */ diff --git a/models/pp_psc_delta.cpp b/models/pp_psc_delta.cpp index 66a4e16606..ad1705c426 100644 --- a/models/pp_psc_delta.cpp +++ b/models/pp_psc_delta.cpp @@ -18,8 +18,10 @@ * You should have received a copy of the GNU General Public License * along with NEST. If not, see . * + */ + +/* * Multimeter support by Yury V. Zaytsev. - * */ /* pp_psc_delta is a stochastically spiking neuron where the potential jumps on each spike arrival. */ @@ -36,6 +38,7 @@ #include + namespace nest { /* ---------------------------------------------------------------- @@ -71,15 +74,21 @@ nest::pp_psc_delta::Parameters_::Parameters_() c_2_ ( 1.238 ), // Hz / mV c_3_ ( 0.25 ), // 1.0 / mV I_e_ ( 0.0 ), // pA - t_ref_remaining_ ( 0.0 ) // ms -{} + t_ref_remaining_ ( 0.0 ), // ms + multi_param_ ( 1 ) +{ + tau_sfa_.clear(); + q_sfa_.clear(); +} nest::pp_psc_delta::State_::State_() : y0_ (0.0), y3_ (0.0), q_ (0.0), r_ (0) -{} +{ + q_elems_.clear(); +} /* ---------------------------------------------------------------- * Parameter and state extractions and manipulation functions @@ -94,12 +103,33 @@ void nest::pp_psc_delta::Parameters_::get(DictionaryDatum &d) const def(d, names::dead_time_random, dead_time_random_); def(d, names::dead_time_shape, dead_time_shape_); def(d, names::with_reset, with_reset_); - def(d, names::tau_sfa, tau_sfa_); - def(d, names::q_sfa, q_sfa_); + def(d, names::c_1, c_1_); def(d, names::c_2, c_2_); def(d, names::c_3, c_3_); def(d, names::t_ref_remaining, t_ref_remaining_); + + if(multi_param_) + { + ArrayDatum tau_sfa_list_ad(tau_sfa_); + def(d,names::tau_sfa, tau_sfa_list_ad); + + ArrayDatum q_sfa_list_ad(q_sfa_); + def(d,names::q_sfa, q_sfa_list_ad); + } + else + { + if(tau_sfa_.size() == 0) + { + def(d, names::tau_sfa, 0); + def(d, names::q_sfa, 0); + } + else + { + def(d, names::tau_sfa, tau_sfa_[0]); + def(d, names::q_sfa, q_sfa_[0]); + } + } } void nest::pp_psc_delta::Parameters_::set(const DictionaryDatum& d) @@ -112,13 +142,29 @@ void nest::pp_psc_delta::Parameters_::set(const DictionaryDatum& d) updateValue(d, names::dead_time_random, dead_time_random_); updateValue(d, names::dead_time_shape, dead_time_shape_); updateValue(d, names::with_reset, with_reset_); - updateValue(d, names::tau_sfa, tau_sfa_); - updateValue(d, names::q_sfa, q_sfa_); updateValue(d, names::c_1, c_1_); updateValue(d, names::c_2, c_2_); updateValue(d, names::c_3, c_3_); updateValue(d, names::t_ref_remaining, t_ref_remaining_); +try{ + updateValue >(d, names::tau_sfa, tau_sfa_); + updateValue >(d, names::q_sfa, q_sfa_); +}catch(TypeMismatch e){ + multi_param_ = 0; + double_t tau_sfa_temp_; + double_t q_sfa_temp_; + updateValue(d, names::tau_sfa, tau_sfa_temp_); + updateValue(d, names::q_sfa, q_sfa_temp_); + tau_sfa_.push_back(tau_sfa_temp_); + q_sfa_.push_back(q_sfa_temp_); +} + + + if (tau_sfa_.size() != q_sfa_.size()) + throw DimensionMismatch(tau_sfa_.size(), q_sfa_.size()); + + if ( c_m_ <= 0 ) throw BadProperty("Capacitance must be strictly positive."); @@ -131,11 +177,17 @@ void nest::pp_psc_delta::Parameters_::set(const DictionaryDatum& d) if ( tau_m_ <= 0 ) throw BadProperty("All time constants must be strictly positive."); - if ( tau_sfa_ <= 0 ) - throw BadProperty("All time constants must be strictly positive."); + for(uint_t i = 0 ; i < tau_sfa_.size() ; i++ ) + if ( tau_sfa_[i] <= 0 ) + throw BadProperty("All time constants must be strictly positive."); if ( t_ref_remaining_ < 0) - throw BadProperty("Remaining refractory time can not be negative"); + throw BadProperty("Remaining refractory time can not be negative."); + + if ( c_3_ < 0) + throw BadProperty("C_3 must be positive."); + + } @@ -200,6 +252,7 @@ void nest::pp_psc_delta::init_buffers_() void nest::pp_psc_delta::calibrate() { + B_.logger_.init(); V_.h_ = Time::get_resolution().get_ms(); @@ -208,7 +261,14 @@ void nest::pp_psc_delta::calibrate() V_.P33_ = std::exp(-V_.h_/P_.tau_m_); V_.P30_ = 1/P_.c_m_*(1-V_.P33_)*P_.tau_m_; - V_.Q33_ = std::exp(-V_.h_/P_.tau_sfa_); + if (P_.dead_time_ != 0 && P_.dead_time_ < V_.h_) + P_.dead_time_ = V_.h_; + + for(uint_t i = 0 ; i < P_.tau_sfa_.size() ; i++){ + V_.Q33_.push_back(std::exp(-V_.h_/P_.tau_sfa_[i])); + S_.q_elems_.push_back(0.0); + } + // TauR specifies the length of the absolute refractory period as // a double_t in ms. The grid based iaf_psp_delta can only handle refractory @@ -250,16 +310,27 @@ void nest::pp_psc_delta::calibrate() void nest::pp_psc_delta::update(Time const & origin, const long_t from, const long_t to) { + assert(to >= 0 && (delay) from < Scheduler::get_min_delay()); assert(from < to); + double_t q_temp_; + for ( long_t lag = from ; lag < to ; ++lag ) { S_.y3_ = V_.P30_*(S_.y0_ + P_.I_e_) + V_.P33_*S_.y3_ + B_.spikes_.get_value(lag); - if (P_.q_sfa_ != 0.0) - S_.q_ = V_.Q33_ * S_.q_; + q_temp_ = 0; + for (uint_t i = 0 ; i < S_.q_elems_.size() ; i++) + { + + S_.q_elems_[i] = V_.Q33_[i] * S_.q_elems_[i]; + + q_temp_ += S_.q_elems_[i]; + } + + S_.q_ = q_temp_; if ( S_.r_ == 0 ) { @@ -271,10 +342,7 @@ void nest::pp_psc_delta::update(Time const & origin, const long_t from, const lo double_t V_eff; - if (P_.q_sfa_ != 0.0) - V_eff = S_.y3_ - S_.q_; - else - V_eff = S_.y3_; + V_eff = S_.y3_ - S_.q_; double_t rate = (P_.c_1_ * V_eff + P_.c_2_ * std::exp(P_.c_3_ * V_eff)); @@ -292,7 +360,7 @@ void nest::pp_psc_delta::update(Time const & origin, const long_t from, const lo { // Draw Poisson random number of spikes V_.poisson_dev_.set_lambda(rate*V_.h_*1e-3); - n_spikes = V_.poisson_dev_.uldev(V_.rng_); + n_spikes = V_.poisson_dev_.ldev(V_.rng_); } if ( n_spikes > 0 ) // Is there a spike? Then set the new dead time. @@ -305,10 +373,12 @@ void nest::pp_psc_delta::update(Time const & origin, const long_t from, const lo else S_.r_ = V_.DeadTimeCounts_; - // Increment the adaptive threshold - if (P_.q_sfa_ != 0.0) - S_.q_ += P_.q_sfa_; + + for(uint_t i = 0 ; i < S_.q_elems_.size() ; i++ ){ + S_.q_elems_[i] += P_.q_sfa_[i]*n_spikes; + } + // And send the spike event SpikeEvent se; se.set_multiplicity(n_spikes); diff --git a/models/pp_psc_delta.h b/models/pp_psc_delta.h index a05391bc44..0dfe2fe0f0 100644 --- a/models/pp_psc_delta.h +++ b/models/pp_psc_delta.h @@ -50,55 +50,70 @@ namespace nest{ generation is followed by an optional dead time. Setting with_reset to true will reset the membrane potential after each spike. - The transfer function can be chosen to be linear, exponential or both by - adjusting three parameters: + The transfer function can be chosen to be linear, exponential or a sum of + both by adjusting three parameters: rate = Rect[ c1 * V' + c2 * exp(c3 * V') ], - where the effective potential V' = V_m - E_sfa and E_sfa is the adaptive - threshold. + where the effective potential V' = V_m - E_sfa and E_sfa is called + the adaptive threshold. By setting c3 = 0, c2 can be used as an offset spike rate for an otherwise - linear model. + linear rate model. The dead time enables to include refractoriness. If dead time is 0, the number of spikes in one time step might exceed one and is drawn from the Poisson distribution accordingly. Otherwise, the probability for a spike - is given by 1 - exp(-rate*h). + is given by 1 - exp(-rate*h), where h is the simulation time step. If dead_time + is smaller than the simulation resolution (time step), it is internally + set to the time step. - Spike generation can then be efficiently simulated by drawing uniform - numbers. So, even if non-refractory neurons are to be modeled, - dead_time=1e-8 might be the value of choice since it uses a faster - random numbers than dead_time=0. Only for large spike rates (> 1 spike/h) - this will cause errors. + Note that, even if non-refractory neurons are to be modeled, a small value + of dead_time, like dead_time=1e-8, might be the value of choice since it + uses faster uniform random numbers than dead_time=0, which draws Poisson + numbers. Only for very large spike rates (> 1 spike/h) this will cause errors. The model can optionally include something which would be called adaptive threshold in an integrate-and-fire neuron. If the neuron spikes, the - threshold goes up and the membrane potential will take longer to reach it. + threshold increases and the membrane potential will take longer to reach it. Here this is implemented by subtracting the value of the adaptive threshold E_sfa from the membrane potential V_m before passing the potential to the - transfer function. E_sfa jumps by q_sfa when the neuron fires a spike, and - decays exponentially with the time constant tau_sfa after (see [2]). - + transfer function, see also above. E_sfa jumps by q_sfa when the neuron + fires a spike, and decays exponentially with the time constant tau_sfa + after (see [2] or [3]). Thus, the E_sfa corresponds to the convolution of the + neuron's spike train with an exponential kernel. + This adaptation kernel may also be chosen as the sum of n exponential + kernels. To use this feature, q_sfa and tau_sfa have to be given as a list + of n values each. + This model has been adapted from iaf_psc_delta. The default parameters are set to the mean values in [2], which have been matched to spike-train recordings. - - - Reference: - - [1] Interacting Poisson processes and applications to neural modeling - Stefano Cardanobile and Stefan Rotter, arXiv:0904.1505 (April 2009) - + + + References: + + [1] Multiplicatively interacting point processes and applications to neural + modeling (2010) Stefano Cardanobile and Stefan Rotter, Journal of + Computational Neuroscience + [2] Predicting spike timing of neocortical pyramidal neurons by simple - threshold models, J Comput Neurosci. Jolivet et al (2006) - + threshold models (2006) Jolivet R, Rauch A, Luescher H-R, Gerstner W. + J Comput Neurosci 21:35-49 + + [3] Pozzorini C, Naud R, Mensi S, Gerstner W (2013) Temporal whitening by + power-law adaptation in neocortical neurons. Nat Neurosci 16: 942-948. + (uses a similar model of multi-timescale adaptation) + + [4] Grytskyy D, Tetzlaff T, Diesmann M and Helias M (2013) A unified view + on weakly correlated recurrent networks. Front. Comput. Neurosci. 7:131. + + Parameters: The following parameters can be set in the status dictionary. V_m double - Membrane potential in mV. - E_sfa double - Adaptive threshold potential in mV. C_m double - Specific capacitance of the membrane in pF/mum^2. tau_m double - Membrane time constant in ms. q_sfa double - Adaptive threshold jump in mV. @@ -114,13 +129,12 @@ namespace nest{ c_3 double - Coefficient of exponential non-linearity of transfer function in 1/mV. - Sends: SpikeEvent Receives: SpikeEvent, CurrentEvent, DataLoggingRequest - Author: July 2009, Deger, Helias; January 2011, Zaytsev - SeeAlso: iaf_psc_delta, iaf_psc_alpha, iaf_psc_exp, iaf_neuron, iaf_psc_delta_canon + Author: July 2009, Deger, Helias; January 2011, Zaytsev; May 2014, Setareh + SeeAlso: pp_pop_psc_delta, iaf_psc_delta, iaf_psc_alpha, iaf_psc_exp, iaf_neuron, iaf_psc_delta_canon */ /** @@ -132,8 +146,6 @@ namespace nest{ public: - typedef Node base; - pp_psc_delta(); pp_psc_delta(const pp_psc_delta&); @@ -199,11 +211,14 @@ namespace nest{ /** Do we reset the membrane potential after each spike? */ bool with_reset_; - /** Adaptive threshold time constant in ms. */ - double_t tau_sfa_; + /** List of adaptive threshold time constant in ms (for multi adaptation version). */ + std::vector tau_sfa_; + + /** Adaptive threshold jump in mV (for multi adaptation version). */ + std::vector q_sfa_; - /** Adaptive threshold jump in mV. */ - double_t q_sfa_; + /** indicates multi parameter adaptation model **/ + bool multi_param_; /** Slope of the linear part of transfer function. */ double_t c_1_; @@ -236,6 +251,8 @@ namespace nest{ double_t y3_; //!< This is the membrane potential RELATIVE TO RESTING POTENTIAL. double_t q_; //!< This is the change of the 'threshold' due to adaptation. + std::vector q_elems_; // Vector of adaptation parameters. by Hesam + int_t r_; //!< Number of refractory steps remaining State_(); //!< Default initialization @@ -270,7 +287,9 @@ namespace nest{ double_t P30_; double_t P33_; - double_t Q33_; + + std::vector Q33_; + double_t h_; //!< simulation time step in ms double_t dt_rate_; //!< rate parameter of dead time distribution diff --git a/models/ppd_sup_generator.cpp b/models/ppd_sup_generator.cpp index 1a2f791182..8fcd41eed0 100644 --- a/models/ppd_sup_generator.cpp +++ b/models/ppd_sup_generator.cpp @@ -50,33 +50,31 @@ nest::ppd_sup_generator::Age_distribution_::Age_distribution_(size_t num_age_bin nest::ulong_t nest::ppd_sup_generator::Age_distribution_::update(double_t hazard_step, librandom::RngPtr rng) { - ulong_t n_spikes; + ulong_t n_spikes; // only set from poisson_dev, bino_dev or 0, thus >= 0 if (occ_active_>0) { /*The binomial distribution converges towards the Poisson distribution as the number of trials goes to infinity while the product np remains fixed. - Therefore the Poisson distribution with parameter λ = np can be used as - an approximation to B(n, p) of the binomial distribution if n is - sufficiently large and p is sufficiently small. According to two rules - of thumb, this approximation is good if n ≥ 20 and p ≤ 0.05, or if - n ≥ 100 and np ≤ 10. Source: + Therefore the Poisson distribution with parameter \lambda = np can be used as + an approximation to B(n, p) of the binomial distribution if n is + sufficiently large and p is sufficiently small. According to two rules + of thumb, this approximation is good if n >= 20 and p <= 0.05, or if + n >= 100 and np <= 10. Source: http://en.wikipedia.org/wiki/Binomial_distribution#Poisson_approximation */ if (( occ_active_ >= 100 && hazard_step <= 0.01 ) || \ ( occ_active_ >= 500 && hazard_step * occ_active_ <= 0.1 )) { poisson_dev_.set_lambda( hazard_step * occ_active_ ); - n_spikes = poisson_dev_.uldev(rng); + n_spikes = poisson_dev_.ldev(rng); if ( n_spikes > occ_active_) { n_spikes = occ_active_; } - else - {;} } else { bino_dev_.set_p_n( hazard_step, occ_active_); - n_spikes = bino_dev_.uldev(rng); + n_spikes = bino_dev_.ldev(rng); } } else @@ -84,14 +82,12 @@ nest::ulong_t nest::ppd_sup_generator::Age_distribution_::update(double_t hazard n_spikes = 0; } - if (occ_refractory_.size()>0) + if ( !occ_refractory_.empty() ) { occ_active_ += occ_refractory_[activate_] - n_spikes; occ_refractory_[activate_] = n_spikes; activate_ = (activate_ + 1) % occ_refractory_.size(); } - else - {;} return n_spikes; } diff --git a/models/ppd_sup_generator.h b/models/ppd_sup_generator.h index 38e16a3340..8680fd2196 100644 --- a/models/ppd_sup_generator.h +++ b/models/ppd_sup_generator.h @@ -81,8 +81,6 @@ namespace nest{ public: - typedef Node base; - ppd_sup_generator(); ppd_sup_generator(const ppd_sup_generator&); diff --git a/models/pulsepacket_generator.cpp b/models/pulsepacket_generator.cpp index 1fa0065fd6..3612e313bb 100644 --- a/models/pulsepacket_generator.cpp +++ b/models/pulsepacket_generator.cpp @@ -179,15 +179,13 @@ void nest::pulsepacket_generator::update(Time const & T, const long_t from, cons } int_t n_spikes = 0 ; - long_t prev_spike = B_.spiketimes_.front(); - // Since we have an ordered list of spiketimes, // we can compute the histogram on the fly. while (!B_.spiketimes_.empty() && B_.spiketimes_.front() < (T.get_steps() + to ) ) { n_spikes++; - prev_spike = B_.spiketimes_.front(); + long_t prev_spike = B_.spiketimes_.front(); B_.spiketimes_.pop_front(); if ( n_spikes > 0 && prev_spike != B_.spiketimes_.front() ) diff --git a/models/quantal_stp_connection.cpp b/models/quantal_stp_connection.cpp new file mode 100644 index 0000000000..c2254718d9 --- /dev/null +++ b/models/quantal_stp_connection.cpp @@ -0,0 +1,194 @@ +/* + * quantal_stp_connection.cpp + * + * This file is part of NEST. + * + * Copyright (C) 2004 The NEST Initiative + * + * NEST 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 2 of the License, or + * (at your option) any later version. + * + * NEST 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 NEST. If not, see . + * + */ + +#include "quantal_stp_connection.h" +#include "network.h" +#include "connection.h" +#include "connector_model.h" +#include "nest_names.h" +#include "dictutils.h" + +namespace nest +{ + + + /** + * Polymorphic version of set_property. + * This version is needed, because DataConnect will pass all properties as doubles. + * This code will take either an int or a double and convert is to an int. + */ + + bool set_property_int(const DictionaryDatum & d, Name propname, index p, int &prop) + { + if (d->known(propname)) + { + ArrayDatum* arrd = dynamic_cast((*d)[propname].datum()); + if (! arrd) + { + ArrayDatum const arrd; + throw TypeMismatch(arrd.gettypename().toString(), + (*d)[propname].datum()->gettypename().toString()); + } + + Datum *dat= (*arrd)[p].datum(); + IntegerDatum *intdat= dynamic_cast(dat); + if(intdat !=0) + { + prop = static_cast(intdat->get()); + return true; + } + DoubleDatum *doubledat= dynamic_cast(dat); + if(doubledat !=0) + { + prop = static_cast(doubledat->get()); + return true; + } + else + throw TypeMismatch(); + } + + return false; + } + + /* Polymorphic version of update_value. + * This version is needed, because DataConnect will pass all properties as doubles. + * This code will take either an int or a double and convert is to an int. + */ + + bool update_value_int(const DictionaryDatum & d, Name propname, int &prop) + { + if (d->known(propname)) + { + Datum *dat= (*d)[propname].datum(); + IntegerDatum *intdat= dynamic_cast(dat); + if(intdat !=0) + { + prop = static_cast(intdat->get()); + return true; + } + DoubleDatum *doubledat= dynamic_cast(dat); + if(doubledat !=0) + { + prop = static_cast(doubledat->get()); + return true; + } + else + throw TypeMismatch(); + } + + return false; + } + + Quantal_StpConnection::Quantal_StpConnection() : + ConnectionHetWD(), + U_(0.5), + u_(U_), + tau_rec_(800.0), + tau_fac_(10.0), + n_(1), + a_(n_) + + { + } + + Quantal_StpConnection::Quantal_StpConnection(const Quantal_StpConnection &rhs) : + ConnectionHetWD(rhs), + U_(rhs.U_), + u_(rhs.u_), + tau_rec_(rhs.tau_rec_), + tau_fac_(rhs.tau_fac_), + n_(rhs.n_), + a_(rhs.a_) + { + } + + + void Quantal_StpConnection::get_status(DictionaryDatum & d) const + { + ConnectionHetWD::get_status(d); + def(d, names::dU, U_); + def(d, names::u, u_); + def(d, names::tau_rec, tau_rec_); + def(d, names::tau_fac, tau_fac_); + def(d, names::n, n_); + def(d, names::a, a_); + } + + + void Quantal_StpConnection::set_status(const DictionaryDatum & d, ConnectorModel &cm) + { + ConnectionHetWD::set_status(d, cm); + + updateValue(d, names::dU, U_); + updateValue(d, names::u, u_); + updateValue(d, names::tau_rec, tau_rec_); + updateValue(d, names::tau_fac, tau_fac_); + updateValue(d, names::weight, weight_); + update_value_int(d, names::n, n_); + update_value_int(d, names::a, a_); + } + + /** + * Set properties of this connection from position p in the properties + * array given in dictionary. + */ + void Quantal_StpConnection::set_status(const DictionaryDatum & d, index p, ConnectorModel &cm) + { + ConnectionHetWD::set_status(d, p, cm); + + set_property(d, names::dUs, p, U_); + set_property(d, names::us, p, u_); + set_property(d, names::tau_recs, p, tau_rec_); + set_property(d, names::tau_facs, p, tau_fac_); + set_property_int(d, names::ns, p, n_); + set_property_int(d, names::as, p, a_); + } + + void Quantal_StpConnection::initialize_property_arrays(DictionaryDatum & d) const + { + ConnectionHetWD::initialize_property_arrays(d); + + initialize_property_array(d, names::dUs); + initialize_property_array(d, names::us); + initialize_property_array(d, names::tau_recs); + initialize_property_array(d, names::tau_facs); + initialize_property_array(d, names::ns); + initialize_property_array(d, names::as); + } + + /** + * Append properties of this connection to the given dictionary. If the + * dictionary is empty, new arrays are created first. + */ + void Quantal_StpConnection::append_properties(DictionaryDatum & d) const + { + ConnectionHetWD::append_properties(d); + + append_property(d, names::dUs, U_); + append_property(d, names::us, u_); + append_property(d, names::tau_recs, tau_rec_); + append_property(d, names::tau_facs, tau_fac_); + append_property(d, names::ns, n_); + append_property(d, names::as, a_); + } + +} // of namespace nest diff --git a/models/quantal_stp_connection.h b/models/quantal_stp_connection.h new file mode 100644 index 0000000000..b99a046b0e --- /dev/null +++ b/models/quantal_stp_connection.h @@ -0,0 +1,197 @@ +/* + * quantal_stp_connection.h + * + * This file is part of NEST. + * + * Copyright (C) 2004 The NEST Initiative + * + * NEST 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 2 of the License, or + * (at your option) any later version. + * + * NEST 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 NEST. If not, see . + * + */ + +#ifndef QUANTAL_STP_CONNECTION_H +#define QUANTAL_STP_CONNECTION_H + +#include "connection_het_wd.h" +#include "binomial_randomdev.h" +#include + +/* BeginDocumentation + Name: quantal_stp_synapse - Probabilistic synapse model with short term plasticity. + + Description: + + This synapse model implements synaptic short-term depression and + short-term facilitation according to the quantal release model + described by Fuhrmann et al. [1] and Loebel et al. [2]. + + Each presynaptic spike will stochastically activate a fraction of + the available release sites. This fraction is binomialy + distributed and the release probability per site is governed by the + Fuhrmann et al. (2002) model. The solution of the differential + equations is taken from Maass and Markram 2002 [3]. + + The connection weight is interpreted as the maximal weight that can + be obtained if all n release sites are activated. + + Parameters: + The following parameters can be set in the status dictionary: + U double - Maximal fraction of available resources [0,1], default=0.5 + u double - available fraction of resources [0,1], default=0.5 + p double - probability that a vesicle is available, default = 1.0 + n long - total number of release sites, default = 1 + a long - number of available release sites, default = n + tau_rec double - time constant for depression in ms, default=800 ms + tau_rec double - time constant for facilitation in ms, default=0 (off) + + + References: + [1] Fuhrmann, G., Segev, I., Markram, H., & Tsodyks, M. V. (2002). Coding of temporal + information by activity-dependent synapses. Journal of neurophysiology, 87(1), 140-8. + [2] Loebel, A., Silberberg, G., Helbig, D., Markram, H., Tsodyks, + M. V, & Richardson, M. J. E. (2009). Multiquantal release underlies + the distribution of synaptic efficacies in the neocortex. Frontiers + in computational neuroscience, 3(November), 27. doi:10.3389/neuro.10.027.2009 + [3] Maass, W., & Markram, H. (2002). Synapses as dynamic memory buffers. Neural networks, 15(2), 155–61. + + Transmits: SpikeEvent + + FirstVersion: December 2013 + Author: Marc-Oliver Gewaltig, based on tsodyks2_synapse + SeeAlso: tsodyks2_synapse, synapsedict, stdp_synapse, static_synapse +*/ + + +/** + * Class representing a synapse with Tsodyks short term plasticity, based on the iterative formula + * A suitable Connector containing these connections can be obtained from the template GenericConnector. + */ + +namespace nest { + +class Quantal_StpConnection : public ConnectionHetWD +{ + public: + + /** + * Default Constructor. + * Sets default values for all parameters. Needed by GenericConnectorModel. + */ + Quantal_StpConnection(); + /** + * Copy constructor to propagate common properties. + */ + Quantal_StpConnection(const Quantal_StpConnection&); + + /** + * Get all properties of this connection and put them into a dictionary. + */ + void get_status(DictionaryDatum & d) const; + + /** + * Set default properties of this connection from the values given in dictionary. + */ + void set_status(const DictionaryDatum & d, ConnectorModel &cm); + + /** + * Set properties of this connection from position p in the properties + * array given in dictionary. + */ + void set_status(const DictionaryDatum & d, index p, ConnectorModel &cm); + + /** + * Create new empty arrays for the properties of this connection in the given + * dictionary. It is assumed that they are not existing before. + */ + void initialize_property_arrays(DictionaryDatum & d) const; + + /** + * Append properties of this connection to the given dictionary. If the + * dictionary is empty, new arrays are created first. + */ + void append_properties(DictionaryDatum & d) const; + + /** + * Send an event to the receiver of this connection. + * \param e The event to send + * \param t_lastspike Point in time of last spike sent. + * \param cp Common properties to all synapses (empty). + */ + void send(Event& e, double_t t_lastspike, const CommonSynapseProperties &); + + // overloaded for all supported event types + using Connection::check_event; + void check_event(SpikeEvent&) {} + + private: + double_t U_; //!< unit increment of a facilitating synapse (U) + double_t u_; //!< dynamic value of probability of release + double_t tau_rec_; //!< [ms] time constant for recovery from depression (D) + double_t tau_fac_; //!< [ms] time constant for facilitation (F) + int n_; //!< Number of release sites + int a_; //!< Number of available release sites +}; + + +/** + * Send an event to the receiver of this connection. + * \param e The event to send + * \param p The port under which this connection is stored in the Connector. + * \param t_lastspike Time point of last spike emitted + * \param cp Common properties object, containing the quantal_stp parameters. + */ +inline +void Quantal_StpConnection::send(Event& e, double_t t_lastspike, const CommonSynapseProperties &) +{ + Network *net=Node::network(); + const int vp=target_->get_vp(); + + const double_t h = e.get_stamp().get_ms() - t_lastspike; + + // Compute the decay factors, based on the time since the last spike. + const double_t p_decay = std::exp(-h/tau_rec_); + const double_t u_decay = (tau_fac_ < 1.0e-10) ? 0.0 : std::exp(-h/tau_fac_); + + // Compute release probability + u_= U_+u_*(1.-U_)*u_decay; // Eq. 4 from [2] + + // Compute number of sites that recovered during the interval. + for (int depleted=n_-a_; depleted > 0; --depleted) + { + if (net->get_rng(vp)->drand() < (1.0-p_decay)) + ++a_; + } + + // Compute number of released sites + int n_release=0; + for (int i=a_; i> 0; --i) + { + if (net->get_rng(vp)->drand() < u_) + ++n_release; + } + + if(n_release>0) + { + e.set_receiver(*target_); + e.set_weight( n_release*weight_); + e.set_delay( delay_ ); + e.set_rport( rport_ ); + e(); + a_ -= n_release; + } +} + +} // namespace + +#endif // QUANTAL_STP_CONNECTION_H diff --git a/models/sinusoidal_poisson_generator.cpp b/models/sinusoidal_poisson_generator.cpp index 67430c68d6..57b2610feb 100644 --- a/models/sinusoidal_poisson_generator.cpp +++ b/models/sinusoidal_poisson_generator.cpp @@ -238,7 +238,7 @@ void nest::sinusoidal_poisson_generator::update(Time const& origin, else { V_.poisson_dev_.set_lambda(S_.rate_ * V_.h_); - ulong_t n_spikes = V_.poisson_dev_.uldev(rng); + long_t n_spikes = V_.poisson_dev_.ldev(rng); SpikeEvent se; se.set_multiplicity(n_spikes); network()->send(*this, se, lag); @@ -251,7 +251,7 @@ void nest::sinusoidal_poisson_generator::event_hook(DSSpikeEvent& e) { librandom::RngPtr rng = net_->get_rng(get_thread()); V_.poisson_dev_.set_lambda(S_.rate_ * V_.h_); - ulong_t n_spikes = V_.poisson_dev_.uldev(rng); + long_t n_spikes = V_.poisson_dev_.ldev(rng); if ( n_spikes > 0 ) // we must not send events with multiplicity 0 { diff --git a/models/sli/models-init.sli b/models/sli/models-init.sli index 31e62b55d1..dcfd54a813 100644 --- a/models/sli/models-init.sli +++ b/models/sli/models-init.sli @@ -22,16 +22,7 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % -% SLI wrappers for functions defined in modelsmodule -% -% Author: Marc-Oliver Gewaltig, Jochen Martin Eppler, Hans Ekkehard Plesser -% Date: September 2008, October 2010 -% - -/models-init /SLI ($Revision: 9031 $) provide-component -/models-init /C++ ($Revision: 9031 $) require-component - -%% Code for the sli_neuron +% Code for the sli_neuron modeldict /sli_neuron known { diff --git a/models/sli_neuron.h b/models/sli_neuron.h index f6aec83da5..f2f3ebeeff 100644 --- a/models/sli_neuron.h +++ b/models/sli_neuron.h @@ -94,8 +94,6 @@ SeeAlso: iaf_psc_delta, iaf_psc_exp, iaf_cond_exp, testsuite::test_sli_neuron { public: - - typedef Node base; sli_neuron(); sli_neuron(const sli_neuron&); diff --git a/models/spike_detector.cpp b/models/spike_detector.cpp index 60591017a0..315515e3d7 100644 --- a/models/spike_detector.cpp +++ b/models/spike_detector.cpp @@ -34,13 +34,17 @@ nest::spike_detector::spike_detector() : Node(), device_(*this, RecordingDevice::SPIKE_DETECTOR, "gdf", true, true), // record time and gid - user_set_precise_times_(false) + user_set_precise_times_(false), + has_proxies_(false), + local_receiver_(true) {} nest::spike_detector::spike_detector(const spike_detector &n) : Node(n), device_(*this, n.device_), - user_set_precise_times_(n.user_set_precise_times_) + user_set_precise_times_(n.user_set_precise_times_), + has_proxies_(false), + local_receiver_(true) {} void nest::spike_detector::init_state_(const Node& np) @@ -96,7 +100,7 @@ void nest::spike_detector::get_status(DictionaryDatum &d) const // if we are the device on thread 0, also get the data from the // siblings on other threads - if (get_thread() == 0) + if (local_receiver_ && get_thread() == 0) { const SiblingContainer* siblings = network()->get_thread_siblings(get_gid()); std::vector::const_iterator sibling; diff --git a/models/spike_detector.h b/models/spike_detector.h index a9b313df23..b0ae60f9da 100644 --- a/models/spike_detector.h +++ b/models/spike_detector.h @@ -101,9 +101,12 @@ namespace nest spike_detector(); spike_detector(const spike_detector&); - bool has_proxies() const { return false; } - bool local_receiver() const {return true;} - + void set_has_proxies(const bool hp); + bool has_proxies() const { return has_proxies_; } + bool potential_global_receiver() const {return true;} + void set_local_receiver(const bool lr); + bool local_receiver() const {return local_receiver_;} + /** * Import sets of overloaded virtual functions. * We need to explicitly include sets of overloaded @@ -122,7 +125,6 @@ namespace nest void set_status(const DictionaryDatum &) ; private: - void init_state_(Node const&); void init_buffers_(); void calibrate(); @@ -166,8 +168,22 @@ namespace nest Buffers_ B_; bool user_set_precise_times_; + bool has_proxies_ ; + bool local_receiver_; }; - + + inline + void spike_detector::set_has_proxies(const bool hp) + { + has_proxies_ = hp; + } + + inline + void spike_detector::set_local_receiver(const bool lr) + { + local_receiver_ = lr; + } + inline port spike_detector::connect_sender(SpikeEvent&, port receptor_type) { diff --git a/models/spike_generator.cpp b/models/spike_generator.cpp index 8066094ac9..a3d895aac3 100644 --- a/models/spike_generator.cpp +++ b/models/spike_generator.cpp @@ -66,9 +66,11 @@ void nest::spike_generator::Parameters_::get(DictionaryDatum &d) const { const size_t n_spikes = spike_stamps_.size(); const size_t n_offsets = spike_offsets_.size(); + assert( ( precise_times_ && n_offsets == n_spikes ) || (!precise_times_ && n_offsets == 0 ) ); + std::vector* times_ms = new std::vector(); times_ms->reserve(n_spikes); for ( size_t n = 0 ; n < n_spikes ; ++n ) @@ -82,12 +84,16 @@ void nest::spike_generator::Parameters_::get(DictionaryDatum &d) const (*d)[names::precise_times] = BoolDatum(precise_times_); (*d)["allow_offgrid_spikes"] = BoolDatum(allow_offgrid_spikes_); (*d)["shift_now_spikes"] = BoolDatum(shift_now_spikes_); + } void nest::spike_generator::Parameters_::assert_valid_spike_time_and_insert_(double t, const Time& origin, const Time& now) { + if (t == 0.0 && !shift_now_spikes_) + throw BadProperty("spike time cannot be set to 0."); + Time t_spike; if ( precise_times_ ) t_spike = Time::ms_stamp(t); @@ -279,7 +285,7 @@ void nest::spike_generator::update(Time const & sliceT0, const long_t from, cons // if we have to deliver weighted spikes, we need to get the // event back to set its weight according to the entry in // spike_weights_, so we use a DSSpike event and event_hook() - if (P_.spike_weights_.size() != 0) + if ( !P_.spike_weights_.empty() ) se = new DSSpikeEvent; else se = new SpikeEvent; diff --git a/models/spike_generator.h b/models/spike_generator.h index b5e5f67e3e..b757def9f8 100644 --- a/models/spike_generator.h +++ b/models/spike_generator.h @@ -47,7 +47,8 @@ namespace nest Spike times are given in milliseconds, and must be sorted with the earliest spike first. All spike times must be strictly in the future. Trying to set a spike time in the past or at the current time step, - will cause a NEST error. + will cause a NEST error. Setting a spike time of 0.0 will also result + in an error. Spike times may not coincide with a time step, i.e., are not a multiple of the simulation resolution. Three options control how spike times that @@ -269,6 +270,7 @@ void spike_generator::get_status(DictionaryDatum &d) const inline void spike_generator::set_status(const DictionaryDatum &d) { + Parameters_ ptmp = P_; // temporary copy in case of errors // To detect "now" spikes and shift them, we need the origin. In case @@ -288,6 +290,7 @@ void spike_generator::set_status(const DictionaryDatum &d) // if we get here, temporary contains consistent set of properties P_ = ptmp; + } diff --git a/models/stdp_connection.cpp b/models/stdp_connection.cpp index af20ad0f75..7da0602751 100644 --- a/models/stdp_connection.cpp +++ b/models/stdp_connection.cpp @@ -1,4 +1,3 @@ - /* * stdp_connection.cpp * diff --git a/models/stdp_connection.h b/models/stdp_connection.h index a80c3c797c..bd225ad889 100644 --- a/models/stdp_connection.h +++ b/models/stdp_connection.h @@ -217,7 +217,7 @@ void STDPConnection::send(Event& e, double_t t_lastspike, const CommonSynapsePro while (start != finish) { minus_dt = t_lastspike - (start->t_ + dendritic_delay); - start++; + ++start; if (minus_dt == 0) continue; weight_ = facilitate_(weight_, Kplus_ * std::exp(minus_dt / tau_plus_)); diff --git a/models/stdp_connection_facetshw_hom.cpp b/models/stdp_connection_facetshw_hom.cpp index 552247bf88..8a786091cc 100644 --- a/models/stdp_connection_facetshw_hom.cpp +++ b/models/stdp_connection_facetshw_hom.cpp @@ -1,16 +1,22 @@ /* * stdp_connection_facetshw_hom.cpp * - * This file is part of NEST + * This file is part of NEST. * - * Copyright (C) 2004 by - * The NEST Initiative + * Copyright (C) 2004 The NEST Initiative * - * See the file AUTHORS for details. + * NEST 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 2 of the License, or + * (at your option) any later version. * - * Permission is granted to compile and modify - * this file for non-commercial use. - * See the file LICENSE for details. + * NEST 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 NEST. If not, see . * */ @@ -297,6 +303,27 @@ namespace nest updateValue(d, "next_readout_time", next_readout_time_); //setting discrete_weight_ does not make sense, is temporary variable + + if (d->known("tau_plus") || + d->known("tau_minus_stdp") || + d->known("Wmax") || + d->known("weight_per_lut_entry") || + d->known("no_synapses") || + d->known("synapses_per_driver") || + d->known("driver_readout_time") || + d->known("readout_cycle_duration") || + d->known("lookuptable_0") || + d->known("lookuptable_1") || + d->known("lookuptable_2") || + d->known("configbit_0") || + d->known("configbit_1") || + d->known("reset_pattern") ) + { + //cm.network().message(SLIInterpreter::M_ERROR, "STDPFACETSHWConnectionHom::set_status()", "you are trying to set common properties via an individual synapse."); + //throw BadParameter(); + throw ChangeCommonPropsByIndividual("STDPPLConnectionHom::set_status(): you are trying to set common properties via an individual synapse."); + } + } /** @@ -322,7 +349,9 @@ namespace nest d->known("configbit_1s") || d->known("reset_patterns") ) { - cm.network().message(SLIInterpreter::M_ERROR, "STDPFACETSHWConnectionHom::set_status()", "you are trying to set common properties via an individual synapse."); + //cm.network().message(SLIInterpreter::M_ERROR, "STDPFACETSHWConnectionHom::set_status()", "you are trying to set common properties via an individual synapse."); + //throw BadParameter(); + throw ChangeCommonPropsByIndividual("STDPPLConnectionHom::set_status(): you are trying to set common properties via an individual synapse."); } } diff --git a/models/stdp_connection_facetshw_hom.h b/models/stdp_connection_facetshw_hom.h index 6f73809cbc..5c2cfbfbd5 100644 --- a/models/stdp_connection_facetshw_hom.h +++ b/models/stdp_connection_facetshw_hom.h @@ -1,16 +1,22 @@ /* * stdp_connection_facetshw_hom.h * - * This file is part of NEST + * This file is part of NEST. * - * Copyright (C) 2004 by - * The NEST Initiative + * Copyright (C) 2004 The NEST Initiative * - * See the file AUTHORS for details. + * NEST 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 2 of the License, or + * (at your option) any later version. * - * Permission is granted to compile and modify - * this file for non-commercial use. - * See the file LICENSE for details. + * NEST 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 NEST. If not, see . * */ diff --git a/models/stdp_connection_hom.cpp b/models/stdp_connection_hom.cpp index 57c0896a0e..36319a80c5 100644 --- a/models/stdp_connection_hom.cpp +++ b/models/stdp_connection_hom.cpp @@ -1,4 +1,3 @@ - /* * stdp_connection_hom.cpp * @@ -97,18 +96,23 @@ namespace nest { // base class properties ConnectionHetWD::set_status(d, cm); + updateValue(d, "Kplus", Kplus_); + + // exception throwing must happen after setting own parameters + // this exception will be caught and ignored within generic_connector_model::set_status() + // it will not be caught if set_status is called directly to signify the specified error + if (d->known("tau_plus") || + d->known("lambda") || + d->known("alpha") || + d->known("mu_plus") || + d->known("mu_minus") || + d->known("Wmax") ) + { + //cm.network().message(SLIInterpreter::M_ERROR, "STDPConnectionHom::set_status()", "you are trying to set common properties via an individual synapse."); + //throw BadParameter(); + throw ChangeCommonPropsByIndividual("STDPConnectionHom::set_status(): you are trying to set common properties via an individual synapse."); + } -// if (d->known("tau_plus") || -// d->known("lambd") || -// d->known("alpha") || -// d->known("mu_plus") || -// d->known("mu_minus") || -// d->known("Wmax") ) -// { -// cm.network().error("STDPConnectionHom::set_status()", "you are trying to set common properties via an individual synapse."); -// } - - updateValue(d, "Kplus", Kplus_); } /** @@ -118,18 +122,19 @@ namespace nest void STDPConnectionHom::set_status(const DictionaryDatum & d, index p, ConnectorModel &cm) { ConnectionHetWD::set_status(d, p, cm); + set_property(d, "Kpluss", p, Kplus_); if (d->known("tau_pluss") || - d->known("lambds") || + d->known("lambdas") || d->known("alphas") || d->known("mu_pluss") || d->known("mu_minuss") || d->known("Wmaxs") ) { - cm.network().message(SLIInterpreter::M_ERROR, "STDPConnectionHom::set_status()", "you are trying to set common properties via an individual synapse."); + //cm.network().message(SLIInterpreter::M_ERROR, "STDPConnectionHom::set_status()", "you are trying to set common properties via an individual synapse."); + throw ChangeCommonPropsByIndividual("STDPConnectionHom::set_status(): you are trying to set common properties via an individual synapse."); } - set_property(d, "Kpluss", p, Kplus_); } void STDPConnectionHom::initialize_property_arrays(DictionaryDatum & d) const diff --git a/models/stdp_connection_hom.h b/models/stdp_connection_hom.h index cd018b7d65..1cb16c5e1d 100644 --- a/models/stdp_connection_hom.h +++ b/models/stdp_connection_hom.h @@ -259,7 +259,7 @@ void STDPConnectionHom::send(Event& e, double_t t_lastspike, const STDPHomCommon while (start != finish) { minus_dt = t_lastspike - (start->t_ + dendritic_delay); - start++; + ++start; if (minus_dt == 0) continue; weight_ = facilitate_(weight_, Kplus_ * std::exp(minus_dt / cp.tau_plus_), cp); diff --git a/models/stdp_dopa_connection.h b/models/stdp_dopa_connection.h index 1ce0388f63..df0e335ca0 100644 --- a/models/stdp_dopa_connection.h +++ b/models/stdp_dopa_connection.h @@ -373,7 +373,7 @@ namespace nest const STDPDopaCommonProperties& cp) { // propagate all state variables to time t_trig - // this does not include the depression trace K_minus, which is updated in the postsyn.neuron + // this does not include the depression trace K_minus, which is updated in the postsyn. neuron // purely dendritic delay double_t dendritic_delay = Time(Time::step(delay_)).get_ms(); @@ -396,7 +396,7 @@ namespace nest } // propagate weight, eligibility trace c, dopamine trace n and facilitation trace K_plus to time t_trig - // but do increment/decrement as there are no spikes to be handled at t_trig + // but do not increment/decrement as there are no spikes to be handled at t_trig process_dopa_spikes_(dopa_spikes, t0, t_trig, cp); n_ = n_ * std::exp( ( dopa_spikes[dopa_spikes_idx_].spike_time_ - t_trig ) / cp.tau_n_ ); Kplus_ = Kplus_ * std::exp( ( t_last_update_ - t_trig ) / cp.tau_plus_); diff --git a/models/stdp_pl_connection_hom.cpp b/models/stdp_pl_connection_hom.cpp index c567d7e34a..3cfed58438 100644 --- a/models/stdp_pl_connection_hom.cpp +++ b/models/stdp_pl_connection_hom.cpp @@ -1,4 +1,3 @@ - /* * stdp_pl_connection_hom.cpp * @@ -91,18 +90,20 @@ namespace nest { // base class properties ConnectionHetWD::set_status(d, cm); + updateValue(d, "Kplus", Kplus_); -// if (d->known("tau_plus") || -// d->known("lambd") || -// d->known("alpha") || -// d->known("mu_plus") || -// d->known("mu_minus") || -// d->known("Wmax") ) -// { -// cm.network().error("STDPPLConnectionHom::set_status()", "you are trying to set common properties via an individual synapse."); -// } + if (d->known("tau_plus") || + d->known("lambda") || + d->known("alpha") || + d->known("mu_plus") || + d->known("mu_minus") || + d->known("Wmax") ) + { + //cm.network().message(SLIInterpreter::M_ERROR, "STDPPLConnectionHom::set_status()", "you are trying to set common properties via an individual synapse."); + //throw BadParameter(); + throw ChangeCommonPropsByIndividual("STDPPLConnectionHom::set_status(): you are trying to set common properties via an individual synapse."); + } - updateValue(d, "Kplus", Kplus_); } /** @@ -112,16 +113,18 @@ namespace nest void STDPPLConnectionHom::set_status(const DictionaryDatum & d, index p, ConnectorModel &cm) { ConnectionHetWD::set_status(d, p, cm); + set_property(d, "Kpluss", p, Kplus_); - if (d->known("tau_pluss") || + if (d->known("tau_pluss") || d->known("lambdas") || d->known("alphas") || - d->known("mus")) + d->known("mus")) { - cm.network().message(SLIInterpreter::M_ERROR, "STDPPLConnectionHom::set_status()", "you are trying to set common properties via an individual synapse."); + //cm.network().message(SLIInterpreter::M_ERROR, "STDPPLConnectionHom::set_status()", "you are trying to set common properties via an individual synapse."); + //throw BadParameter(); + throw ChangeCommonPropsByIndividual("STDPPLConnectionHom::set_status(): you are trying to set common properties via an individual synapse."); } - set_property(d, "Kpluss", p, Kplus_); } void STDPPLConnectionHom::initialize_property_arrays(DictionaryDatum & d) const diff --git a/models/stdp_pl_connection_hom.h b/models/stdp_pl_connection_hom.h index 8922f9c68e..80b11750b4 100644 --- a/models/stdp_pl_connection_hom.h +++ b/models/stdp_pl_connection_hom.h @@ -232,7 +232,7 @@ void STDPPLConnectionHom::send(Event& e, double_t t_lastspike, const STDPPLHomCo while (start != finish) { minus_dt = t_lastspike - (start->t_ + dendritic_delay); - start++; + ++start; if (minus_dt == 0) continue; weight_ = facilitate_(weight_, Kplus_ * std::exp(minus_dt / cp.tau_plus_), cp); diff --git a/models/tsodyks2_connection.cpp b/models/tsodyks2_connection.cpp index 53512c9bfd..8323403611 100644 --- a/models/tsodyks2_connection.cpp +++ b/models/tsodyks2_connection.cpp @@ -32,7 +32,7 @@ namespace nest ConnectionHetWD(), U_(0.5), u_(U_), - x_(U_), + x_(1), tau_rec_(800.0), tau_fac_(0.0) { diff --git a/models/tsodyks2_connection.h b/models/tsodyks2_connection.h index ebc56c3e5c..f33456534e 100644 --- a/models/tsodyks2_connection.h +++ b/models/tsodyks2_connection.h @@ -62,6 +62,7 @@ depends on neurotransmitter release probability. PNAS, 94(2), 719-23. [2] Fuhrmann, G., Segev, I., Markram, H., & Tsodyks, M. V. (2002). Coding of temporal information by activity-dependent synapses. Journal of neurophysiology, 87(1), 140-8. + [3] Maass, W., & Markram, H. (2002). Synapses as dynamic memory buffers. Neural networks, 15(2), 155–61. Transmits: SpikeEvent @@ -152,19 +153,22 @@ inline void Tsodyks2Connection::send(Event& e, double_t t_lastspike, const CommonSynapseProperties &) { double_t h = e.get_stamp().get_ms() - t_lastspike; - double_t f = std::exp(-h/tau_rec_); + double_t x_decay = std::exp(-h/tau_rec_); double_t u_decay = (tau_fac_ < 1.0e-10) ? 0.0 : std::exp(-h/tau_fac_); - x_= x_*(1.0-u_)*f + u_*(1.0-f); // Eq. 2 from reference [1] - u_ *= u_decay; - u_+= U_*(1.0-u_); // for tau_fac=0 and u_=0, this will render u_==U_ + // now we compute spike number n+1 + x_= 1. + (x_ -x_*u_ -1.)*x_decay; // Eq. 5 from reference [3] + u_= U_+u_*(1.-U_)*u_decay; // Eq. 4 from [3] - // send the spike to the target + // We use the current values for the spike number n. e.set_receiver(*target_); - e.set_weight( x_*weight_ ); + e.set_weight( x_*u_*weight_ ); + // send the spike to the target e.set_delay( delay_ ); e.set_rport( rport_ ); e(); + + } } // namespace diff --git a/nest/Makefile.am b/nest/Makefile.am index 51bc3ea803..1799e79e40 100644 --- a/nest/Makefile.am +++ b/nest/Makefile.am @@ -38,9 +38,26 @@ nest_LDADD= @LINKED_USER_MODULES@ \ @SLI_LIBS@\ @GSL_LIBS@\ @MUSIC_LIBS@\ - @MPI_LIBS@ + @MPI_LIBS@\ + @LIBNEUROSIM_LIBS@ -nest_DEPENDENCIES = @LINKED_MODULES@ \ +# ZYV: +# +# The dependencies here have to be specified manually all over again, +# instead of relying on the autotools dependency generation magic from the +# LDADD primary, because of the awesomeness in how LINKED_MODULES +# is constructed. Since these are not relative paths, autotools can't +# figure out whether it's a local convenience library or not and just +# drops these libraries from the dependency list. +# +# I sincerely hope that it gets busted when some brave soul will take +# on the build system rewrite. +# +# Automake 1.11.3+ makes it a bit less painfull: +# +# EXTRA_nest_DEPENDENCIES = @LINKED_MODULES@ @LINKED_USER_MODULES@ + +nest_DEPENDENCIES = @LINKED_MODULES@ @LINKED_USER_MODULES@ \ $(top_builddir)/nestkernel/libnest.la \ $(top_builddir)/librandom/librandom.la \ $(top_builddir)/libnestutil/libnestutil.la \ @@ -50,4 +67,4 @@ AM_CPPFLAGS= -I$(top_srcdir)/libnestutil\ -I$(top_srcdir)/librandom\ -I$(top_srcdir)/sli\ -I$(top_srcdir)/nestkernel\ - @GSL_CFLAGS@ @MUSIC_INCLUDE@ @MPI_INCLUDE@ + @GSL_CFLAGS@ @MUSIC_INCLUDE@ @MPI_INCLUDE@ @LIBNEUROSIM_INCLUDE@ diff --git a/nest/main.cpp b/nest/main.cpp index 73adcff2c3..4c4c617eec 100644 --- a/nest/main.cpp +++ b/nest/main.cpp @@ -21,27 +21,14 @@ */ #include + #include "neststartup.h" -#include "communicator.h" -#include "interpret.h" -#include "booldatum.h" -#include "dictdatum.h" -#include "network.h" -// OpenMP -#ifdef _OPENMP -#include -#endif +#include "network.h" +#include "interpret.h" int main(int argc, char *argv[]) { -#ifdef HAVE_MPI - nest::Communicator::init(&argc, &argv); -#endif - -#ifdef _OPENMP - omp_set_num_threads(1); -#endif nest::Network *pNet = 0; @@ -57,9 +44,7 @@ int main(int argc, char *argv[]) // start the interpreter session int exitcode = engine.execute(); -#ifdef HAVE_MPI - nest::Communicator::finalize(); -#endif + nestshutdown(); // delete the Network before modules are deleted by interpreter's destructor // because otherwise models defined in a module might still be referenced by diff --git a/nest/neststartup.cpp b/nest/neststartup.cpp index a7eb2b47de..88740efe67 100644 --- a/nest/neststartup.cpp +++ b/nest/neststartup.cpp @@ -20,19 +20,24 @@ * */ -/* - This code will be used to startup NEST. It will be called only - for starting NEST as a stand-alone application. Similar code is - found in PyNEST. -*/ - #include "config.h" + +#include "neststartup.h" + #include + +#include "network.h" #include "interpret.h" +#include "communicator.h" + #include "dict.h" #include "dictdatum.h" #include "random_numbers.h" + +#ifndef _IS_PYNEST #include "gnureadline.h" +#endif + #include "slistartup.h" #include "sliarray.h" #include "oosupport.h" @@ -43,13 +48,29 @@ #include "sligraphics.h" #include "dynamicloader.h" #include "filesystem.h" -#include "neststartup.h" #include "static_modules.h" -int neststartup(int argc, char**argv, SLIInterpreter &engine, nest::Network* &pNet) +// OpenMP +#ifdef _OPENMP +#include +#endif + +#ifndef _IS_PYNEST +int neststartup(int argc, char** argv, SLIInterpreter &engine, nest::Network* &pNet) +#else +int neststartup(int argc, char** argv, SLIInterpreter &engine, nest::Network* &pNet, std::string modulepath) +#endif { +#ifdef HAVE_MPI + nest::Communicator::init(&argc, &argv); +#endif + +#ifdef _OPENMP + omp_set_num_threads(1); +#endif + // We disable synchronization between stdio and istd::ostreams // this has to be done before any in- or output has been done. /* @@ -69,9 +90,11 @@ int neststartup(int argc, char**argv, SLIInterpreter &engine, nest::Network* &pN addmodule(engine); addmodule(engine); -#ifdef HAVE_READLINE + +#if defined(HAVE_READLINE) && !defined(_IS_PYNEST) addmodule(engine); #endif + addmodule(engine); addmodule(engine); // safe without GSL addmodule(engine); @@ -89,7 +112,7 @@ int neststartup(int argc, char**argv, SLIInterpreter &engine, nest::Network* &pN // now add static modules providing models add_static_modules(engine, *pNet); -#ifdef HAVE_LIBLTDL // no dynamic loading without LIBLTDL +#ifdef HAVE_LIBLTDL //dynamic loader module for managing linked and dynamically loaded extension modules nest::DynamicLoaderModule *pDynLoader = new nest::DynamicLoaderModule(pNet, engine); @@ -102,5 +125,34 @@ int neststartup(int argc, char**argv, SLIInterpreter &engine, nest::Network* &pN engine.addmodule(pDynLoader); #endif +#ifdef _IS_PYNEST + // add the init-script to the list of module initializers + ArrayDatum *ad = dynamic_cast(engine.baselookup(engine.commandstring_name).datum()); + assert(ad != NULL); + ad->push_back(new StringDatum("(" + modulepath + "/pynest-init.sli) run")); +#endif + return engine.startup(); } + +void nestshutdown(void) +{ +#ifdef HAVE_MPI + nest::Communicator::finalize(); +#endif +} + +#if defined(HAVE_LIBNEUROSIM) && defined(_IS_PYNEST) +Datum* CYTHON_unpackConnectionGeneratorDatum(PyObject* obj) +{ + Datum* ret = NULL; + ConnectionGenerator* cg = NULL; + + cg = PNS::unpackConnectionGenerator(obj); + + if (cg != NULL) + ret = static_cast(new nest::ConnectionGeneratorDatum(cg)); + + return ret; +} +#endif diff --git a/nest/neststartup.h b/nest/neststartup.h index 89984baabe..3d358a8898 100644 --- a/nest/neststartup.h +++ b/nest/neststartup.h @@ -1,5 +1,3 @@ -#ifndef NEST_STARTUP_H -#define NEST_STARTUP_H /* * neststartup.h * @@ -22,14 +20,42 @@ * */ +#ifndef NEST_STARTUP_H +#define NEST_STARTUP_H + +#if defined(HAVE_LIBNEUROSIM) && defined(_IS_PYNEST) + +#include + +#include "datum.h" +#include "conngenmodule.h" + +#define CYTHON_isConnectionGenerator(x) PNS::isConnectionGenerator(x) +Datum* CYTHON_unpackConnectionGeneratorDatum(PyObject*); + +#else +#define CYTHON_isConnectionGenerator(x) 0 +#define CYTHON_unpackConnectionGeneratorDatum(x) NULL +#endif + namespace nest { class Network; } class SLIInterpreter; +#ifdef _IS_PYNEST + +#define CYTHON_DEREF(x) (*x) +#define CYTHON_ADDR(x) (&x) + +#include +int neststartup(int argc, char** argv, SLIInterpreter &engine, nest::Network* &pNet, std::string modulepath = ""); + +#else +int neststartup(int argc, char** argv, SLIInterpreter &engine, nest::Network* &pNet); +#endif -int pyneststartup(int argc, char**argv, SLIInterpreter &engine, nest::Network* &pNet); -int neststartup(int argc, char**argv, SLIInterpreter &engine, nest::Network* &pNet); +void nestshutdown(void); #endif diff --git a/nestkernel/Makefile.am b/nestkernel/Makefile.am index b7bf98a7de..b922c58742 100644 --- a/nestkernel/Makefile.am +++ b/nestkernel/Makefile.am @@ -32,12 +32,10 @@ libnest_la_SOURCES=\ communicator.h communicator_impl.h communicator.cpp\ sibling_container.h sibling_container.cpp\ subnet.h subnet.cpp\ - multirange.h multirange.cpp\ connection.h connection.cpp\ connection_het_wd.h connection_het_wd.cpp\ connection_hom_wd.h connection_hom_wd.cpp\ connection_manager.h connection_manager.cpp\ - connectiondatum.h connectiondatum.cpp\ connection_id.h connection_id.cpp\ connector.h\ connector_model.h connector_model.cpp\ @@ -49,10 +47,12 @@ libnest_la_SOURCES=\ generic_connector.h\ generic_connector_model.h\ genericmodel.h\ + gid_collection.h gid_collection.cpp\ bg_get_mem.c\ histentry.h histentry.cpp\ model.h model.cpp\ nest.h\ + nest_datums.h nest_datums.cpp\ nest_names.cpp nest_names.h\ nestmodule.h nestmodule.cpp\ nest_time.h nest_time.cpp \ @@ -61,7 +61,8 @@ libnest_la_SOURCES=\ net_thread.h net_thread.cpp\ modelrange.h modelrange.cpp\ modelrangemanager.h modelrangemanager.cpp\ - network.h network.cpp\ + multirange.h multirange.cpp\ + network.h network_impl.h network.cpp\ node.h node.cpp\ nodelist.h nodelist.cpp\ proxynode.h proxynode.cpp\ @@ -71,6 +72,9 @@ libnest_la_SOURCES=\ scheduler.h scheduler.cpp\ spikecounter.h spikecounter.cpp\ stimulating_device.h\ + conn_parameter.h conn_parameter.cpp\ + conn_builder.h conn_builder.cpp\ + conn_builder_factory.h\ music_event_handler.h music_event_handler.cpp libnest_la_LIBADD= @LIBLTDL@ @LIBADD_DL@ diff --git a/nestkernel/archiving_node.cpp b/nestkernel/archiving_node.cpp index 9b1b5dc653..40b8e9358f 100644 --- a/nestkernel/archiving_node.cpp +++ b/nestkernel/archiving_node.cpp @@ -62,7 +62,7 @@ namespace nest { for ( std::deque::iterator runner = history_.begin(); runner != history_.end() && runner->t_ <= t_first_read; - runner++) + ++runner) (runner->access_counter_)++; n_incoming_++; @@ -77,7 +77,7 @@ namespace nest { for ( std::deque::iterator runner = history_.begin(); runner != history_.end() && runner->t_ <= t_last_read; - runner++) + ++runner) (runner->access_counter_)--; n_incoming_--; @@ -136,12 +136,12 @@ namespace nest { else { std::deque::iterator runner = history_.begin(); - while ((runner != history_.end()) && (runner->t_ <= t1)) runner++; + while ((runner != history_.end()) && (runner->t_ <= t1)) ++runner; *start = runner; - while ((runner != history_.end()) && (runner->t_ <= t2)) + while ((runner != history_.end()) && (runner->t_ <= t2)) { (runner->access_counter_)++; - runner++; + ++runner; } *finish = runner; } diff --git a/nestkernel/bg_get_mem.c b/nestkernel/bg_get_mem.c index e2ce6cae98..96645b9a5c 100644 --- a/nestkernel/bg_get_mem.c +++ b/nestkernel/bg_get_mem.c @@ -21,6 +21,7 @@ */ #include "config.h" +#include "assert.h" #if defined IS_BLUEGENE_P || defined IS_BLUEGENE_Q @@ -46,4 +47,19 @@ unsigned long bg_get_stack_mem() return (unsigned long)memory; } +#else + +/* ISO C forbids an empty translation unit, so we define dummies. */ +unsigned long bg_get_heap_mem() +{ + assert(0 || "Only implemented on BlueGene."); + return 0; +} + +unsigned long bg_get_stack_mem() +{ + assert(0 || "Only implemented on BlueGene."); + return 0; +} + #endif diff --git a/nestkernel/common_synapse_properties.cpp b/nestkernel/common_synapse_properties.cpp index 2f1f7efcbc..58eb0a7d78 100644 --- a/nestkernel/common_synapse_properties.cpp +++ b/nestkernel/common_synapse_properties.cpp @@ -1,4 +1,3 @@ - /* * common_synapse_properties.cpp * @@ -21,7 +20,6 @@ * */ - #include "nest.h" #include "dictdatum.h" #include "common_synapse_properties.h" @@ -45,7 +43,6 @@ namespace nest { Node* CommonSynapseProperties::get_node() {return 0;} - void CommonSynapseProperties::calibrate(const TimeConverter &) {} } // namespace nest diff --git a/nestkernel/communicator.cpp b/nestkernel/communicator.cpp index ada9826f04..fe375a0502 100644 --- a/nestkernel/communicator.cpp +++ b/nestkernel/communicator.cpp @@ -68,6 +68,7 @@ MPI_Comm comm=0; template<> MPI_Datatype MPI_Type::type = MPI_INT; template<> MPI_Datatype MPI_Type::type = MPI_DOUBLE; template<> MPI_Datatype MPI_Type::type = MPI_LONG; +template<> MPI_Datatype MPI_Type::type = MPI_INT; MPI_Datatype MPI_OFFGRID_SPIKE = 0; @@ -78,10 +79,9 @@ unsigned int nest::Communicator::COMM_OVERFLOW_ERROR = std::numeric_limits nest::Communicator::comm_step_ = std::vector(); /** - * Set up MPI, establish number of processes and rank, and initialize - * the vector of communication partners. + * Set up MPI and establish number of processes and rank */ -void nest::Communicator::init (int* argc, char** argv[]) +void nest::Communicator::init(int* argc, char** argv[]) { /* Initialize MPI @@ -144,7 +144,9 @@ void nest::Communicator::init (int* argc, char** argv[]) //generate and commit struct MPI_Type_struct(2, blockcounts, offsets, source_types, &MPI_OFFGRID_SPIKE); MPI_Type_commit(&MPI_OFFGRID_SPIKE); - init_communication(); + //set up order of communication if using CPEX + if (! use_Allgather_) + init_communication(); initialized_ = true; } @@ -153,7 +155,7 @@ void nest::Communicator::init (int* argc, char** argv[]) */ void nest::Communicator::finalize() { - MPI_Type_free (&MPI_OFFGRID_SPIKE); + MPI_Type_free(&MPI_OFFGRID_SPIKE); int finalized; MPI_Finalized(&finalized); @@ -236,9 +238,9 @@ void nest::Communicator::init_communication () } } -void nest::Communicator::communicate (std::vector& send_buffer, - std::vector& recv_buffer, - std::vector& displacements) +void nest::Communicator::communicate(std::vector& send_buffer, + std::vector& recv_buffer, + std::vector& displacements) { if (num_processes_ == 1) //purely thread-based { @@ -256,9 +258,9 @@ void nest::Communicator::communicate (std::vector& send_buffer, communicate_CPEX(send_buffer, recv_buffer,displacements); } -void nest::Communicator::communicate_Allgather (std::vector& send_buffer, - std::vector& recv_buffer, - std::vector& displacements) +void nest::Communicator::communicate_Allgather(std::vector& send_buffer, + std::vector& recv_buffer, + std::vector& displacements) { std::vector recv_counts(num_processes_,send_buffer_size_); @@ -304,9 +306,9 @@ void nest::Communicator::communicate_Allgather (std::vector& send_buffer } } -void nest::Communicator::communicate_CPEX (std::vector& send_buffer, - std::vector& recv_buffer, - std::vector& displacements) +void nest::Communicator::communicate_CPEX(std::vector& send_buffer, + std::vector& recv_buffer, + std::vector& displacements) { MPI_Status status; int partner; @@ -460,9 +462,9 @@ void nest::Communicator::communicate_Allgather(std::vector& send_buffer, } } -void nest::Communicator::communicate (std::vector& send_buffer, - std::vector& recv_buffer, - std::vector& displacements) +void nest::Communicator::communicate(std::vector& send_buffer, + std::vector& recv_buffer, + std::vector& displacements) { if (num_processes_ == 1) //purely thread-based { @@ -480,9 +482,9 @@ void nest::Communicator::communicate (std::vector& send_buffer, communicate_CPEX(send_buffer, recv_buffer,displacements); } -void nest::Communicator::communicate_Allgather (std::vector& send_buffer, - std::vector& recv_buffer, - std::vector& displacements) +void nest::Communicator::communicate_Allgather(std::vector& send_buffer, + std::vector& recv_buffer, + std::vector& displacements) { std::vector recv_counts(num_processes_,send_buffer_size_); //attempt Allgather @@ -528,9 +530,9 @@ void nest::Communicator::communicate_Allgather (std::vector& send_ } } -void nest::Communicator::communicate_CPEX (std::vector& send_buffer, - std::vector& recv_buffer, - std::vector& displacements) +void nest::Communicator::communicate_CPEX(std::vector& send_buffer, + std::vector& recv_buffer, + std::vector& displacements) { MPI_Status status; int partner; @@ -654,11 +656,10 @@ void nest::Communicator::communicate(std::vector& send_buffer, { //get size of buffers std::vector n_nodes(num_processes_); - n_nodes[Communicator::rank_] = send_buffer.size(); + n_nodes[rank_] = send_buffer.size(); communicate(n_nodes); // Set up displacements vector. displacements.resize(num_processes_,0); - for ( int i = 1; i < num_processes_; ++i ) displacements.at(i) = displacements.at(i-1)+n_nodes.at(i-1); @@ -782,7 +783,7 @@ bool nest::Communicator::grng_synchrony(unsigned long process_rnd_number) return true; } -//average communication time for a packet size of num_bytes +//average communication time for a packet size of num_bytes using Allgather nest::double_t nest::Communicator::time_communicate(int num_bytes, int samples) { if (num_processes_ == 1) @@ -803,7 +804,35 @@ nest::double_t nest::Communicator::time_communicate(int num_bytes, int samples) double_t total_duration = (double)(finishtime-starttime); return total_duration/(samples * sysconf(_SC_CLK_TCK)); } - + +//average communication time for a packet size of num_bytes using Allgatherv +nest::double_t nest::Communicator::time_communicatev(int num_bytes, int samples) +{ + if (num_processes_ == 1) + return 0.0; + uint_t packet_length = num_bytes/sizeof(uint_t); + if (packet_length < 1) + packet_length = 1; + std::vector test_send_buffer(packet_length); + std::vector test_recv_buffer(packet_length*num_processes_); + std::vector n_nodes(num_processes_,packet_length) ; + std::vector displacements(num_processes_,0) ; + + for ( int i = 1; i < num_processes_; ++i ) + displacements.at(i) = displacements.at(i-1)+n_nodes.at(i-1); + + //start time measurement here + struct tms foo; + const clock_t starttime = times(&foo); + for (int i = 0; i < samples; ++i) + communicate_Allgatherv(test_send_buffer, test_recv_buffer, displacements, n_nodes); + + //finish time measurement here + const clock_t finishtime = times(&foo); + double_t total_duration = (double)(finishtime-starttime); + return total_duration/(samples * sysconf(_SC_CLK_TCK)); +} + //average communication time for a packet size of num_bytes nest::double_t nest::Communicator::time_communicate_offgrid(int num_bytes, int samples) { @@ -930,9 +959,9 @@ void nest::Communicator::advance_music_time(long_t num_steps) /** * communicate (on-grid) if compiled without MPI */ -void nest::Communicator::communicate (std::vector& send_buffer, - std::vector& recv_buffer, - std::vector& displacements) +void nest::Communicator::communicate(std::vector& send_buffer, + std::vector& recv_buffer, + std::vector& displacements) { displacements[0] = 0; if (static_cast(recv_buffer_size_) < send_buffer.size()) @@ -946,9 +975,9 @@ void nest::Communicator::communicate (std::vector& send_buffer, /** * communicate (off-grid) if compiled without MPI */ -void nest::Communicator::communicate (std::vector& send_buffer, - std::vector& recv_buffer, - std::vector& displacements) +void nest::Communicator::communicate(std::vector& send_buffer, + std::vector& recv_buffer, + std::vector& displacements) { displacements[0] = 0; if (static_cast(recv_buffer_size_) < send_buffer.size()) diff --git a/nestkernel/communicator.h b/nestkernel/communicator.h index 34ab562788..26b39ccb14 100644 --- a/nestkernel/communicator.h +++ b/nestkernel/communicator.h @@ -191,6 +191,7 @@ class Communicator static bool grng_synchrony(unsigned long); static double_t time_communicate(int num_bytes, int samples=1000); + static double_t time_communicatev(int num_bytes, int samples=1000); static double_t time_communicate_offgrid(int num_bytes, int samples=1000); static std::string get_processor_name(); @@ -203,7 +204,7 @@ class Communicator static int get_recv_buffer_size(); static bool get_use_Allgather(); static bool get_initialized(); - + static void set_num_threads(thread num_threads); static void set_buffer_sizes(int send_buffer_size, int recv_buffer_size); static void set_use_Allgather(bool use_Allgather); @@ -219,7 +220,7 @@ class Communicator static int recv_buffer_size_; //!< size of receive buffer static bool initialized_; //!< whether MPI is initialized static bool use_Allgather_; //!< using Allgather communication - + static std::vector comm_step_; //!< array containing communication partner for each step. static uint_t COMM_OVERFLOW_ERROR; @@ -253,6 +254,11 @@ class Communicator static void communicate_CPEX(std::vector&); }; +inline void Communicator::set_use_Allgather(bool use_Allgather) +{ + use_Allgather_ = use_Allgather; +} + } #else /* #ifdef HAVE_MPI */ @@ -346,6 +352,7 @@ class Communicator */ static bool grng_synchrony(unsigned long) {return true;} static double_t time_communicate(int, int){return 0.0;} + static double_t time_communicatev(int, int){return 0.0;} static double_t time_communicate_offgrid(int, int){return 0.0;} static std::string get_processor_name(); @@ -376,6 +383,12 @@ class Communicator static bool use_Allgather_; //!< using Allgather communication }; +inline void Communicator::set_use_Allgather(bool use_Allgather) +{ + use_Allgather_ = use_Allgather; +} + + inline std::string Communicator::get_processor_name() { char name[1024]; @@ -441,11 +454,6 @@ inline void Communicator::set_buffer_sizes(int send_buffer_size, int recv_buffer recv_buffer_size_ = recv_buffer_size; } -inline void Communicator::set_use_Allgather(bool use_Allgather) -{ - use_Allgather_ = use_Allgather; -} - } // namespace nest #endif /* #ifndef COMMUNICATOR_H */ diff --git a/nestkernel/communicator_impl.h b/nestkernel/communicator_impl.h index 8479116d7e..9e52e997a7 100644 --- a/nestkernel/communicator_impl.h +++ b/nestkernel/communicator_impl.h @@ -265,7 +265,6 @@ void nest::Communicator::communicate(const NodeListType& local_nodes, vectorget_gid(); DictionaryDatum node_status = net.get_status(gid); - node_status->info(std::cout); for (Dictionary::iterator i = params->begin(); i != params->end(); ++i) { if (node_status->known(i->first)) diff --git a/nestkernel/conn_builder.cpp b/nestkernel/conn_builder.cpp new file mode 100644 index 0000000000..510b1f76a4 --- /dev/null +++ b/nestkernel/conn_builder.cpp @@ -0,0 +1,782 @@ +/* + * conn_builder.cpp + * + * This file is part of NEST. + * + * Copyright (C) 2004 The NEST Initiative + * + * NEST 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 2 of the License, or + * (at your option) any later version. + * + * NEST 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 NEST. If not, see . + * + */ + +#include "conn_builder.h" +#include "conn_parameter.h" + +#include "dict.h" +#include "name.h" +#include "nest_names.h" +#include "network.h" +#include "node.h" +#include "exceptions.h" + +#include "gsl_binomial_randomdev.h" +#include "normal_randomdev.h" +#include "gslrandomgen.h" +#include "fdstream.h" + +#include +#ifdef _OPENMP +#include +#endif + +nest::ConnBuilder::ConnBuilder(Network& net, + const GIDCollection& sources, + const GIDCollection& targets, + const DictionaryDatum& conn_spec, + const DictionaryDatum& syn_spec + ) + : net_(net), + sources_(sources), + targets_(targets), + autapses_(true), + multapses_(true), + exceptions_raised_(net_.get_num_threads()), + synapse_model_(net_.get_synapsedict()["static_synapse"]), + weight_(0), + delay_(0), + param_dicts_() +{ + // read out rule-related parameters ------------------------- + // - /rule has been taken care of above + // - rule-specific params are handled by subclass c'tor + updateValue(conn_spec, names::autapses, autapses_); + updateValue(conn_spec, names::multapses, multapses_); + + // read out synapse-related parameters ---------------------- + if ( !syn_spec->known(names::model) ) + throw BadProperty("Synapse spec must contain synapse model."); + const std::string syn_name = (*syn_spec)[names::model]; + if ( !net_.get_synapsedict().known(syn_name) ) + throw UnknownSynapseType(syn_name); + + // if another synapse than static_synapse is defined we need to make sure that Connect can process all parameter specified + if ( syn_name != "static_synapse" ) + check_synapse_params_(syn_name, syn_spec); + + synapse_model_ = net_.get_synapsedict()[syn_name]; + + DictionaryDatum syn_defaults = net_.get_connector_defaults(synapse_model_); + + // If neither weight or delay are given in the dict, we handle this + // separately. Important for hom_wd synapses, on which weight and delay + // cannot be set. + default_weight_and_delay_ = ( !syn_spec->known(names::weight) + && !syn_spec->known(names::delay) ); + if ( !default_weight_and_delay_ ) + { + weight_ = syn_spec->known(names::weight) + ? ConnParameter::create((*syn_spec)[names::weight]) + : ConnParameter::create((*syn_defaults)[names::weight]); + delay_ = syn_spec->known(names::delay) + ? ConnParameter::create((*syn_spec)[names::delay]) + : ConnParameter::create((*syn_defaults)[names::delay]); + } + + // synapse-specific parameters + // TODO: Can we create this set once and for all? + // Should not be done as static initialization, since + // that might conflict with static initialization of + // Name system. + std::set skip_set; + skip_set.insert(names::weight); + skip_set.insert(names::delay); + skip_set.insert(Name("min_delay")); + skip_set.insert(Name("max_delay")); + skip_set.insert(Name("node_type")); + skip_set.insert(Name("num_connections")); + skip_set.insert(Name("num_connectors")); + skip_set.insert(Name("property_object")); + skip_set.insert(Name("synapsemodel")); + + for ( Dictionary::const_iterator default_it = syn_defaults->begin(); + default_it != syn_defaults->end(); + ++default_it + ) + { + const Name param_name = default_it->first; + if ( skip_set.find(param_name) != skip_set.end() ) + continue; // weight, delay or not-settable parameter + + if ( syn_spec->known(param_name) ) + synapse_params_[param_name] = ConnParameter::create((*syn_spec)[param_name]); + } + + // Now create dictionary with dummy values that we will use + // to pass settings to the synapses created. We create it here + // once to avoid re-creating the object over and over again. + if ( synapse_params_.size() > 0 ) + { + for ( thread t = 0 ; t < net_.get_num_threads() ; ++t ) + { + param_dicts_.push_back(new Dictionary()); + + for ( ConnParameterMap::const_iterator it = synapse_params_.begin() ; + it != synapse_params_.end(); + ++it ) + { + if ( it->first == names::receptor_type ) + (*param_dicts_[t])[it->first] = Token(new IntegerDatum(0)); + else + (*param_dicts_[t])[it->first] = Token(new DoubleDatum(0.0)); + } + } + } +} + + +nest::ConnBuilder::~ConnBuilder() +{ + delete weight_; + delete delay_; + for ( std::map::iterator + it = synapse_params_.begin(); + it != synapse_params_.end(); + ++it ) + delete it->second; +} + +inline +void nest::ConnBuilder::check_synapse_params_(std::string syn_name, const DictionaryDatum& syn_spec) +{ + // throw error if weight or delay are specified with static_synapse_hom_wd + if ( syn_name == "static_synapse_hom_wd" ) + { + if ( syn_spec->known(names::delay) or syn_spec->known(names::weight) ) + throw BadProperty("Weight and delay cannot be specified since they need to be equal " + "for all connections when static_synapse_hom_wd is used."); + return; + } + + + // throw error if n or a are set in quantal_stp_synapse, Connect cannot handle them since they are integer + if ( syn_name == "quantal_stp_synapse" ) + { + if ( syn_spec->known(names::n) ) + throw NotImplemented("Connect doesn't support the setting of parameter " + "n in quantal_stp_synapse. Use SetDefaults() or CopyModel()."); + if ( syn_spec->known(names::a) ) + throw NotImplemented("Connect doesn't support the setting of parameter " + "a in quantal_stp_synapse. Use SetDefaults() or CopyModel()."); + return; + } + + // print warning if delay is specified outside cont_delay_synapse + if ( syn_name == "cont_delay_synapse" ) + { + if ( syn_spec->known(names::delay) ) + net_.message(SLIInterpreter::M_WARNING, "Connect", + "The delay will be rounded to the next multiple of the time step. " + "To use a more precise time delay it needs to be defined within " + "the synapse, e.g. with CopyModel()."); + return; + } + + // throw error if no volume transmitter is defined or parameters are specified that need to be introduced via CopyModel or SetDefaults + if ( syn_name == "stdp_dopamine_synapse" ) + { + if ( syn_spec->known("vt") ) + throw NotImplemented("Connect doesn't support the direct specification of the " + "volume transmitter of stdp_dopamine_synapse in syn_spec." + "Use SetDefaults() or CopyModel()."); + // setting of parameter c and n not thread save + if ( net_.get_num_threads() > 1) + { + if ( syn_spec->known(names::c) ) + throw NotImplemented("For multi-threading Connect doesn't support the setting " + "of parameter c in stdp_dopamine_synapse. " + "Use SetDefaults() or CopyModel()."); + if ( syn_spec->known(names::n) ) + throw NotImplemented("For multi-threading Connect doesn't support the setting " + "of parameter n in stdp_dopamine_synapse. " + "Use SetDefaults() or CopyModel()."); + } + std::string param_arr[] = { "A_minus", "A_plus", "Wmax", "Wmin", "b", "tau_c", + "tau_n", "tau_plus" }; + std::vector param_vec(param_arr, param_arr+8); + for ( std::vector::iterator + it = param_vec.begin(); + it != param_vec.end(); + it ++ + ) + { + if ( syn_spec->known(*it) ) + throw NotImplemented("Connect doesn't support the setting of parameter " + *it + + " in stdp_dopamine_synapse. Use SetDefaults() or CopyModel()."); + } + return; + } +} + +void nest::ConnBuilder::connect() +{ + connect_(); + + // check if any exceptions have been raised + for ( thread thr = 0 ; thr < net_.get_num_threads() ; ++thr ) + if ( exceptions_raised_.at(thr).valid() ) + throw WrappedThreadException(*(exceptions_raised_.at(thr))); +} + +inline +void nest::ConnBuilder::single_connect_(index sgid, index tgid, + Node& target, thread target_thread, librandom::RngPtr& rng) +{ + if ( param_dicts_.empty() ) // indicates we have no synapse params + { + if ( default_weight_and_delay_ ) + net_.connect(sgid, tgid, &target, target_thread, + synapse_model_); + else + net_.connect(sgid, tgid, &target, target_thread, + weight_->value_double(sgid, tgid, rng), + delay_->value_double(sgid, tgid, rng), + synapse_model_); + } + else + { + assert(net_.get_num_threads() == static_cast(param_dicts_.size())); + + for ( ConnParameterMap::const_iterator it = synapse_params_.begin() ; + it != synapse_params_.end(); + ++it ) + { + if ( it->first == names::receptor_type ) + { + try + { + // change value of dictionary entry without allocating new datum + IntegerDatum *id = static_cast(((*param_dicts_[target_thread])[it->first]).datum_without_tagging_as_accessed()); + (*id) = it->second->value_int(sgid, tgid, rng); + } + catch(KernelException& e) + { + throw BadProperty("Receptor type must be of type integer."); + } + } + else + { + // change value of dictionary entry without allocating new datum + DoubleDatum *dd = static_cast(((*param_dicts_[target_thread])[it->first]).datum_without_tagging_as_accessed()); + (*dd) = it->second->value_double(sgid, tgid, rng); + } + } + + if ( default_weight_and_delay_ ) + net_.connect(sgid, tgid, &target, target_thread, + param_dicts_[target_thread], synapse_model_); + else + net_.connect(sgid, tgid, &target, target_thread, + weight_->value_double(sgid, tgid, rng), + delay_->value_double(sgid, tgid, rng), + param_dicts_[target_thread], synapse_model_); + } +} + +void nest::OneToOneBuilder::connect_() +{ + // make sure that target and source population have the same size + if (sources_.size() != targets_.size()) + { + net_.message(SLIInterpreter::M_ERROR, "Connect", + "Source and Target population must be of the same size."); + throw DimensionMismatch(); + } + + #pragma omp parallel + { + // get thread id + const int tid = net_.get_thread_id(); + + try + { + // allocate pointer to thread specific random generator + librandom::RngPtr rng = net_.get_rng(tid); + + for ( GIDCollection::const_iterator tgid = targets_.begin(), sgid = sources_.begin(); + tgid != targets_.end(); + ++tgid, ++sgid ) + { + assert(sgid != sources_.end()); + + if (*sgid == *tgid and not autapses_) + continue; + + // check whether the target is on this mpi machine + if (!net_.is_local_gid(*tgid)) + continue; + + Node * const target = net_.get_node(*tgid); + const thread target_thread = target->get_thread(); + + // check whether the target is on our thread + if( tid != target_thread) + continue; + + single_connect_(*sgid, *tgid, *target, target_thread, rng); + } + } + catch ( std::exception& err ) + { + // We must create a new exception here, err's lifetime ends at + // the end of the catch block. + exceptions_raised_.at(tid) = lockPTR(new WrappedThreadException(err)); + } + } +} + +void nest::AllToAllBuilder::connect_() +{ + + #pragma omp parallel + { + // get thread id + const int tid = net_.get_thread_id(); + + try + { + // allocate pointer to thread specific random generator + librandom::RngPtr rng = net_.get_rng(tid); + + for (GIDCollection::const_iterator + tgid = targets_.begin(); + tgid != targets_.end(); + ++tgid + ) + { + // check whether the target is on this mpi machine + if (!net_.is_local_gid(*tgid)) + continue; + + Node * const target = net_.get_node(*tgid); + const thread target_thread = target->get_thread(); + + // check whether the target is on our thread + if( tid != target_thread) + continue; + + for ( GIDCollection::const_iterator + sgid = sources_.begin(); + sgid != sources_.end(); + ++sgid ) + { + if (not autapses_ and *sgid == *tgid) + continue; + + single_connect_(*sgid, *tgid, *target, target_thread, rng); + } + } + } + catch ( std::exception& err ) + { + // We must create a new exception here, err's lifetime ends at + // the end of the catch block. + exceptions_raised_.at(tid) = lockPTR(new WrappedThreadException(err)); + } + } +} + +nest::FixedInDegreeBuilder::FixedInDegreeBuilder(Network& net, + const GIDCollection& sources, + const GIDCollection& targets, + const DictionaryDatum& conn_spec, + const DictionaryDatum& syn_spec + ) + : ConnBuilder(net, sources, targets, conn_spec, syn_spec), + indegree_((*conn_spec)[Name("indegree")]) +{ + // check for potential errors + + // verify that indegree is not larger than source population if multapses are disabled + if (not multapses_ ) + { + if ((indegree_ > static_cast(sources_.size()))) + throw BadProperty("Indegree cannot be larger than population size."); + } + +} + +void nest::FixedInDegreeBuilder::connect_() +{ + #pragma omp parallel + { + // get thread id + const int tid = net_.get_thread_id(); + + try + { + // allocate pointer to thread specific random generator + librandom::RngPtr rng = net_.get_rng(tid); + + for (GIDCollection::const_iterator + tgid = targets_.begin(); + tgid != targets_.end(); + ++tgid + ) + { + // check whether the target is on this mpi machine + if (!net_.is_local_gid(*tgid)) + continue; + + Node * const target = net_.get_node(*tgid); + const thread target_thread = target->get_thread(); + + // check whether the target is on our thread + if( tid != target_thread) + continue; + + std::set ch_ids; + long n_rnd = sources_.size(); + + for (long j = 0; j < indegree_; ++j) + { + unsigned long s_id; + index sgid; + + do + { + s_id = rng->ulrand(n_rnd); + sgid = sources_[s_id]; + } + while (( not autapses_ and sgid == *tgid ) || + ( not multapses_ and ch_ids.find( s_id ) != ch_ids.end())); + + if (not multapses_) + ch_ids.insert(s_id); + + single_connect_(sgid, *tgid, *target, target_thread, rng); + } + } + } + catch ( std::exception& err ) + { + // We must create a new exception here, err's lifetime ends at + // the end of the catch block. + exceptions_raised_.at(tid) = lockPTR(new WrappedThreadException(err)); + } + } +} + +nest::FixedOutDegreeBuilder::FixedOutDegreeBuilder(Network& net, + const GIDCollection& sources, + const GIDCollection& targets, + const DictionaryDatum& conn_spec, + const DictionaryDatum& syn_spec + ) + : ConnBuilder(net, sources, targets, conn_spec, syn_spec), + outdegree_((*conn_spec)[Name("outdegree")]) +{ + // check for potential errors + + // verify that outdegree is not larger than target population if multapses are disabled + if (not multapses_ ) + { + if ((outdegree_ > static_cast(targets_.size()))) + throw BadProperty("Outdegree cannot be larger than population size."); + } +} + +void nest::FixedOutDegreeBuilder::connect_() +{ + librandom::RngPtr grng = net_.get_grng(); + + for (GIDCollection::const_iterator + sgid = sources_.begin(); + sgid != sources_.end(); + ++sgid + ) + { + std::set ch_ids; + std::vector tgt_ids_; + const long n_rnd = targets_.size(); + + for ( long j = 0; j < outdegree_ ; ++j ) + { + unsigned long t_id; + index tgid; + + do + { + t_id = grng->ulrand(n_rnd); + tgid = targets_[t_id]; + } + while (( not autapses_ and tgid == *sgid ) || + ( not multapses_ and ch_ids.find( t_id ) != ch_ids.end())); + + if (not multapses_) + ch_ids.insert(t_id); + + tgt_ids_.push_back(tgid); + } + + #pragma omp parallel + { + // get thread id + const int tid = net_.get_thread_id(); + + try + { + // allocate pointer to thread specific random generator + librandom::RngPtr rng = net_.get_rng(tid); + + for (std::vector::const_iterator + tgid = tgt_ids_.begin(); + tgid != tgt_ids_.end(); + ++tgid + ) + { + // check whether the target is on this mpi machine + if (!net_.is_local_gid(*tgid)) + continue; + + Node * const target = net_.get_node(*tgid); + const thread target_thread = target->get_thread(); + + // check whether the target is on our thread + if( tid != target_thread) + continue; + + single_connect_(*sgid, *tgid, *target, target_thread, rng); + } + } + catch ( std::exception& err ) + { + // We must create a new exception here, err's lifetime ends at + // the end of the catch block. + exceptions_raised_.at(tid) = lockPTR(new WrappedThreadException(err)); + } + } + } +} + +nest::FixedTotalNumberBuilder::FixedTotalNumberBuilder(Network& net, + const GIDCollection& sources, + const GIDCollection& targets, + const DictionaryDatum& conn_spec, + const DictionaryDatum& syn_spec + ) + : ConnBuilder(net, sources, targets, conn_spec, syn_spec), + N_((*conn_spec)[Name("N")]) +{ + + // check for potential errors + + // verify that total number of connections is not larger than N_sources*N_targets + if (not multapses_ ) + { + if ((N_ > static_cast(sources_.size()*targets_.size()))) + throw BadProperty("Total number of connections cannot exceed product " + "of source and targer population sizes."); + } + + // for now multapses cannot be forbidden + // TODO: Implement option for multapses_ = False, where already existing connections are stored in a bitmap + if (not multapses_) + throw NotImplemented("Connect doesn't support the suppression of multapses in the " + "FixedTotalNumber connector."); +} + +void nest::FixedTotalNumberBuilder::connect_() +{ + #ifdef HAVE_GSL + const int_t M = Communicator::get_num_virtual_processes(); + const long_t size_sources = sources_.size(); + const long_t size_targets = targets_.size(); + + // drawing connection ids + + // Compute the distribution of targets over processes using the modulo function + std::vector > targets_on_vp(M); + for (size_t t = 0; t < targets_.size(); t++) + { + targets_on_vp[net_.suggest_vp(targets_[t])].push_back(targets_[t]); + } + + // We use the multinomial distribution to determine the number of + // connections that will be made on one virtual process, i.e. we + // partition the set of edges into n_vps subsets. The number of + // edges on one virtual process is binomially distributed with + // the boundary condition that the sum of all edges over virtual + // processes is the total number of edges. + // To obtain the num_conns_on_vp we adapt the gsl + // implementation of the multinomial distribution. + + // K from gsl is equivalent to M = n_vps + // N is already taken from stack + // p[] is targets_on_vp + std::vector num_conns_on_vp (M, 0); // corresponds to n[] + + // calculate exact multinomial distribution + // get global rng that is tested for synchronization for all threads + librandom::RngPtr grng = net_.get_grng(); + + // HEP: instead of counting upwards, we might count remaining_targets and remaining_partitions down. why? + // begin code adapted from gsl 1.8 // + double_t sum_dist = 0.0; // corresponds to sum_p + //norm is equivalent to size_targets + uint_t sum_partitions = 0; // corresponds to sum_n + // substituting gsl_ran call + librandom::GSL_BinomialRandomDev bino(grng, 0, 0); + + for (int k = 0; k < M; k++ ) + { + if (targets_on_vp[k].size() > 0) + { + double_t num_local_targets = static_cast (targets_on_vp[k].size()); + double_t p_local = num_local_targets / (size_targets - sum_dist); + bino.set_p(p_local); + bino.set_n(N_ - sum_partitions); + num_conns_on_vp[k] = bino.ldev(); + } + + sum_dist += static_cast (targets_on_vp[k].size()); + sum_partitions += static_cast (num_conns_on_vp[k]); + } + + // end code adapted from gsl 1.8 + + #pragma omp parallel + { + // get thread id + const int tid = net_.get_thread_id(); + + try + { + // allocate pointer to thread specific random generator + const int_t vp_id = net_.thread_to_vp(tid); + + if(net_.is_local_vp(vp_id)) + { + librandom::RngPtr rng = net_.get_rng(tid); + + while( num_conns_on_vp[vp_id] > 0 ) + { + + // draw random numbers for source node from all source neurons + const long_t s_index = rng->ulrand(size_sources); + // draw random numbers for target node from + // targets_on_vp on this virtual process + const long_t t_index = rng->ulrand(targets_on_vp[vp_id].size()); + // map random number of source node to gid corresponding to + // the source_adr vector + const long_t sgid = sources_[s_index]; + // map random number of target node to gid using the + // targets_on_vp vector + const long_t tgid = targets_on_vp[vp_id][t_index]; + + Node * const target = net_.get_node(tgid); + const thread target_thread = target->get_thread(); + + if ( autapses_ or sgid != tgid ) + { + single_connect_(sgid, tgid, *target, target_thread, rng); + num_conns_on_vp[vp_id]--; + } + } + } + } + catch ( std::exception& err ) + { + // We must create a new exception here, err's lifetime ends at + // the end of the catch block. + exceptions_raised_.at(tid) = lockPTR(new WrappedThreadException(err)); + } + } + #else + throw NotImplemented("The FixedTotalNumber connector requires the GSL."); + #endif +} + + +nest::BernoulliBuilder::BernoulliBuilder(Network& net, + const GIDCollection& sources, + const GIDCollection& targets, + const DictionaryDatum& conn_spec, + const DictionaryDatum& syn_spec + ) + : ConnBuilder(net, sources, targets, conn_spec, syn_spec), + p_((*conn_spec)[Name("p")]) +{} + + +void nest::BernoulliBuilder::connect_() +{ + #pragma omp parallel + { + // get thread id + const int tid = net_.get_thread_id(); + + try + { + // allocate pointer to thread specific random generator + librandom::RngPtr rng = net_.get_rng(tid); + + for (GIDCollection::const_iterator + tgid = targets_.begin(); + tgid != targets_.end(); + ++tgid + ) + { + // check whether the target is on this mpi machine + if (!net_.is_local_gid(*tgid)) + continue; + + Node * const target = net_.get_node(*tgid); + const thread target_thread = target->get_thread(); + + // check whether the target is on our thread + if( tid != target_thread) + continue; + + std::set ch_ids; + + for ( GIDCollection::const_iterator + sgid = sources_.begin(); + sgid != sources_.end(); + ++sgid ) + { + if(not multapses_ and ch_ids.find( *sgid ) != ch_ids.end()) + continue; + + if (not autapses_ and *sgid == *tgid) + continue; + + if (not ( rng->drand() < p_ )) + continue; + + if (not multapses_) + ch_ids.insert(*sgid); + + single_connect_(*sgid, *tgid, *target, target_thread, rng); + } + } + } + catch ( std::exception& err ) + { + // We must create a new exception here, err's lifetime ends at + // the end of the catch block. + exceptions_raised_.at(tid) = lockPTR(new WrappedThreadException(err)); + } + } +} + diff --git a/nestkernel/conn_builder.h b/nestkernel/conn_builder.h new file mode 100644 index 0000000000..f85105c6ac --- /dev/null +++ b/nestkernel/conn_builder.h @@ -0,0 +1,222 @@ +/* + * conn_builder.h + * + * This file is part of NEST. + * + * Copyright (C) 2004 The NEST Initiative + * + * NEST 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 2 of the License, or + * (at your option) any later version. + * + * NEST 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 NEST. If not, see . + * + */ + +#ifndef CONN_BUILDER_H +#define CONN_BUILDER_H + +/** + * Class managing flexible connection creation. + * + * This is a very first draft, a very much stripped-down version of the + * Topology connection_creator. + * + */ + +#include +#include + +#include "dictdatum.h" +#include "gid_collection.h" +#include "lockptr.h" +#include "sliexceptions.h" + +#include "gslrandomgen.h" + +namespace nest { + + class Network; + class Node; + class ConnParameter; + + /** + * Abstract base class for ConnBuilders. + * + * The base class extracts and holds parameters and provides + * the connect interface. Derived classes implement the connect + * method. + * + * @note Naming classes *Builder to avoid name confusion with Connector classes. + */ + + class ConnBuilder + { + public: + + /** + * Connect sources to targets according to specifications in dictionary. + * + * To create a connection, call + * + * cb.connect(); + * + * where conn_spec_dict speficies connection type and its parameters. + */ + virtual void connect(); + + //! parameters: sources, targets, specifications + ConnBuilder(Network&, + const GIDCollection&, const GIDCollection&, + const DictionaryDatum&, const DictionaryDatum&); + virtual ~ConnBuilder(); + + protected: + + //! Implements the actual connection algorithm + virtual void connect_() =0; + + //! Create connection between given nodes, fill parameter values + void single_connect_(index, index, Node&, thread, librandom::RngPtr&); + + Network& net_; + + const GIDCollection& sources_; + const GIDCollection& targets_; + + bool autapses_; + bool multapses_; + + //! buffer for exceptions raised in threads + std::vector > exceptions_raised_; + + private: + typedef std::map ConnParameterMap; + + index synapse_model_; + + //! indicate that weight and delay should not be set per synapse + bool default_weight_and_delay_; + + // null-pointer indicates that default be used + ConnParameter* weight_; + ConnParameter* delay_; + + //! all other parameters, mapping name to value representation + ConnParameterMap synapse_params_; + + //! dictionaries to pass to connect function, one per thread + std::vector param_dicts_; + + // check for synapse specific errors or warnings + // This is a temporary function which should be removed once all parameter types work with Connect. + // The remaining error and warnings should then be handled within the synapse model. + void check_synapse_params_(std::string, const DictionaryDatum& ); + }; + + class OneToOneBuilder : public ConnBuilder + { + public: + OneToOneBuilder(Network& net, + const GIDCollection& sources, + const GIDCollection& targets, + const DictionaryDatum& conn_spec, + const DictionaryDatum& syn_spec) + : ConnBuilder(net, sources, targets, conn_spec, syn_spec) + {} + + protected: + void connect_(); + }; + + class AllToAllBuilder : public ConnBuilder + { + public: + AllToAllBuilder(Network& net, + const GIDCollection& sources, + const GIDCollection& targets, + const DictionaryDatum& conn_spec, + const DictionaryDatum& syn_spec) + : ConnBuilder(net, sources, targets, conn_spec, syn_spec) + {} + + protected: + void connect_(); + }; + + + class FixedInDegreeBuilder : public ConnBuilder + { + public: + FixedInDegreeBuilder(Network&, + const GIDCollection&, + const GIDCollection&, + const DictionaryDatum&, + const DictionaryDatum&); + + protected: + void connect_(); + + private: + long indegree_; + }; + + class FixedOutDegreeBuilder : public ConnBuilder + { + public: + FixedOutDegreeBuilder(Network&, + const GIDCollection&, + const GIDCollection&, + const DictionaryDatum&, + const DictionaryDatum&); + + protected: + void connect_(); + + private: + long outdegree_; + }; + + class FixedTotalNumberBuilder : public ConnBuilder + { + public: + FixedTotalNumberBuilder(Network&, + const GIDCollection&, + const GIDCollection&, + const DictionaryDatum&, + const DictionaryDatum&); + + protected: + void connect_(); + + private: + long N_; + }; + + class BernoulliBuilder : public ConnBuilder + { + public: + BernoulliBuilder(Network&, + const GIDCollection&, + const GIDCollection&, + const DictionaryDatum&, + const DictionaryDatum&); + + protected: + void connect_(); + + private: + double p_; //!< connection probability + }; + + +} // namespace nest + +#endif diff --git a/nestkernel/conn_builder_factory.h b/nestkernel/conn_builder_factory.h new file mode 100644 index 0000000000..286affdf79 --- /dev/null +++ b/nestkernel/conn_builder_factory.h @@ -0,0 +1,75 @@ +/* + * conn_builder_factory.h + * + * This file is part of NEST. + * + * Copyright (C) 2004 The NEST Initiative + * + * NEST 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 2 of the License, or + * (at your option) any later version. + * + * NEST 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 NEST. If not, see . + * + */ + +#ifndef CONN_BUILDER_FACTORY_H +#define CONN_BUILDER_FACTORY_H + +#include +#include "name.h" +#include "dictdatum.h" +#include "lockptrdatum.h" +#include "conn_builder.h" + +namespace nest { + + class Network; + + /** + * Generic factory class for ConnBuilder objects. + * + * This factory allows for flexible registration + * of ConnBuilder subclasses and object creation. + * + */ + class GenericConnBuilderFactory { + public: + virtual ~GenericConnBuilderFactory() {} + virtual ConnBuilder* create(Network&, + const GIDCollection&, + const GIDCollection&, + const DictionaryDatum&, + const DictionaryDatum&) const =0; + }; + + /** + * Factory class for generating objects of type ConnBuilder + */ + + template + class ConnBuilderFactory : public GenericConnBuilderFactory { + + public: + + //! create conn builder + ConnBuilder* create(Network& net, + const GIDCollection& sources, + const GIDCollection& targets, + const DictionaryDatum& conn_spec, + const DictionaryDatum& syn_spec) const + { + return new ConnBuilderType(net, sources, targets, conn_spec, syn_spec); + } + }; + +} // namespace nest + +#endif diff --git a/nestkernel/conn_parameter.cpp b/nestkernel/conn_parameter.cpp new file mode 100644 index 0000000000..efcf6263af --- /dev/null +++ b/nestkernel/conn_parameter.cpp @@ -0,0 +1,78 @@ +/* + * conn_parameter.cpp + * + * This file is part of NEST. + * + * Copyright (C) 2004 The NEST Initiative + * + * NEST 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 2 of the License, or + * (at your option) any later version. + * + * NEST 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 NEST. If not, see . + * + */ + +#include "conn_parameter.h" +#include "arraydatum.h" +#include "doubledatum.h" +#include "integerdatum.h" +#include "random_numbers.h" +#include "random_datums.h" +#include "nest_names.h" +#include "tokenutils.h" + +nest::ConnParameter* nest::ConnParameter::create(const Token& t) +{ + // Code grabbed from TopologyModule::create_parameter() + // See there for a more general solution + + // single double + DoubleDatum *dd = dynamic_cast(t.datum()); + if ( dd ) + return new ScalarDoubleParameter(*dd); + + // random deviate + DictionaryDatum *rdv_spec = dynamic_cast(t.datum()); + if ( rdv_spec ) + return new RandomParameter(*rdv_spec); + + // single integer + IntegerDatum *id = dynamic_cast(t.datum()); + if ( id ) + return new ScalarIntegerParameter(*id); + + // array + DoubleVectorDatum *dvd = dynamic_cast(t.datum()); + if ( dvd ) + throw NotImplemented("Cannot handle parameter type."); + //return new ArrayParameter(**dvd); + + throw BadProperty("Cannot handle parameter type."); + + return 0; +} + +nest::RandomParameter::RandomParameter(const DictionaryDatum& rdv_spec) + : rdv_(0) +{ + if ( !rdv_spec->known(names::distribution) ) + throw BadProperty("Random distribution spec must contain distribution name."); + + const std::string rdv_name = (*rdv_spec)[names::distribution]; + if ( !RandomNumbers::get_rdvdict().known(rdv_name) ) + throw BadProperty("Unknown random deviate: " + rdv_name); + + librandom::RdvFactoryDatum factory + = getValue(RandomNumbers::get_rdvdict()[rdv_name]); + + rdv_ = factory->create(); + rdv_->set_status(rdv_spec); +} diff --git a/nestkernel/conn_parameter.h b/nestkernel/conn_parameter.h new file mode 100644 index 0000000000..d929149c72 --- /dev/null +++ b/nestkernel/conn_parameter.h @@ -0,0 +1,171 @@ +/* + * conn_parameter.h + * + * This file is part of NEST. + * + * Copyright (C) 2004 The NEST Initiative + * + * NEST 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 2 of the License, or + * (at your option) any later version. + * + * NEST 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 NEST. If not, see . + * + */ + +#ifndef CONN_PARAMETER_H +#define CONN_PARAMETER_H + +#include +#include + +#include "randomgen.h" +#include "randomdev.h" +#include "token.h" +#include "exceptions.h" + +/** + * Base class for parameters provided to connection routines. + * + * Principles for these parameters are + * - Each parameter is a single scalar value. + * - The parameter will be returned as type double. + * - The parameter values can be given either as + * - a single scalar: the same value is returned for each call + * - a random deviate generator: a new random values is returned for each call + * - an array of scalars: values are returned in order + */ + +namespace nest +{ + + class ConnParameter + { + public: + ConnParameter() {} + virtual ~ConnParameter() {} + + /** + * Return parameter value. + * + * The parameter value may depend on source and target GIDs + * (when using callback functions, not yet implemented) + * and random numbers. All three must be supplied, even if + * a concrete parameter type does not use them. + * + * @param sgid source gid + * @param tgid target gid + * @param rng random number generator pointer + * will be ignored except for random parameters. + */ + virtual double value_double(index, index, librandom::RngPtr&) const =0; + virtual long_t value_int(index, index, librandom::RngPtr&) const =0; + + /** + * Returns number of values available. + * + * 0 indicates scalar/unlimited supply. + */ + virtual size_t number_of_values() const { return 0; } + + static ConnParameter* create(const Token&); + }; + + + /** + * Single double value. + * + * On each request, it returns the same value. + */ + class ScalarDoubleParameter: public ConnParameter + { + public: + ScalarDoubleParameter(double value) : value_(value) {} + + double value_double(index, index, librandom::RngPtr&) const { return value_; } + long_t value_int(index, index, librandom::RngPtr&) const { throw KernelException("ConnParameter calls value function with false return type."); } + + private: + double value_; + }; + + /** + * Single integer value. + * + * On each request, it returns the same value. + */ + class ScalarIntegerParameter: public ConnParameter + { + public: + ScalarIntegerParameter(long_t value) : value_(value) {} + + double value_double(index, index, librandom::RngPtr&) const { throw KernelException("ConnParameter calls value function with false return type."); } + long_t value_int(index, index, librandom::RngPtr&) const { return value_; } + + private: + long_t value_; + }; + + + /** + * Array parameter, returning values in order. + * + * - The array of values must not be empty + * (so return 0 for number_of_values can signal non-array parameter) + * - Throws exception if more values requested than available. + * + */ + class ArrayParameter: public ConnParameter + { + public: + ArrayParameter(const std::vector& values) + : values_(values), next_(values_.begin()) + {} + + size_t number_of_values() const { return values_.size(); } + + //double value(index sgid, index tgid, librandom::RngPtr&) const + double value_double(index, index, librandom::RngPtr&) const + + { + //return values_[sgid]; + if ( next_ != values_.end() ) + return *next_++; + else + throw KernelException("Parameter values exhausted."); + } + long_t value_int(index, index, librandom::RngPtr&) const { throw KernelException("ConnParameter calls value function with false return type."); } + + private: + std::vector values_; + mutable std::vector::iterator next_; + }; + + + /** + * Random scalar value. + * + * On each request, it returns a new value drawn from the given deviate. + */ + class RandomParameter: public ConnParameter + { + public: + RandomParameter(const DictionaryDatum&); + + double value_double(index, index, librandom::RngPtr& rng) const { return (*rdv_)(rng); } + long_t value_int(index, index, librandom::RngPtr& rng) const { return (*rdv_)(rng); } + + private: + librandom::RdvPtr rdv_; + }; + +} // namespace nest + +#endif diff --git a/nestkernel/connection.h b/nestkernel/connection.h index 20a8f743fc..d85df93428 100644 --- a/nestkernel/connection.h +++ b/nestkernel/connection.h @@ -225,8 +225,7 @@ bool set_property(const DictionaryDatum & d, Name propname, index p, PropT &prop { if (d->known(propname)) { - ArrayDatum* arrd = 0; - arrd = dynamic_cast((*d)[propname].datum()); + ArrayDatum* arrd = dynamic_cast((*d)[propname].datum()); if (! arrd) { ArrayDatum const arrd; diff --git a/nestkernel/connection_id.cpp b/nestkernel/connection_id.cpp index 11c43b78eb..759165b8b0 100644 --- a/nestkernel/connection_id.cpp +++ b/nestkernel/connection_id.cpp @@ -70,25 +70,18 @@ namespace nest bool ConnectionID::operator==(const ConnectionID& c) const { return (source_gid_ == c.source_gid_) - && (target_gid_ == c.target_gid_) + && (target_gid_ == c.target_gid_) && (target_thread_ == c.target_thread_) && (port_ == c.port_) && (synapse_modelid_ == c.synapse_modelid_); } - std::ostream & ConnectionID::print_me(std::ostream& out) const + void ConnectionID::print_me(std::ostream& out) const { - out << "((" << source_gid_ << ',' << target_gid_<< ',' - << target_thread_ << ',' << synapse_modelid_ << ',' - << port_ << "))"; - return out; + out << "<" << source_gid_ << "," << target_gid_ << "," + << target_thread_ << "," << synapse_modelid_ << "," << port_ << ">"; } -std::ostream & operator<<(std::ostream& out, const nest::ConnectionID& c) -{ - return c.print_me(out); -} - } // namespace diff --git a/nestkernel/connection_id.h b/nestkernel/connection_id.h index 3172082df5..082f3623c1 100644 --- a/nestkernel/connection_id.h +++ b/nestkernel/connection_id.h @@ -31,7 +31,7 @@ namespace nest class ConnectionID { - public: + public: ConnectionID() {} ConnectionID(long source_gid, long target_gid, long target_thread, long synapse_modelid, long port); @@ -42,7 +42,7 @@ namespace nest DictionaryDatum get_dict() const; ArrayDatum to_ArrayDatum() const; bool operator==(const ConnectionID& c) const; - std::ostream & print_me(std::ostream& out) const; + void print_me(std::ostream& out) const; long get_source_gid() const; long get_target_gid() const; long get_target_thread() const; @@ -94,8 +94,6 @@ namespace nest { return port_; } - - std::ostream & operator<<(std::ostream& , const ConnectionID&); } // namespace diff --git a/nestkernel/connection_manager.cpp b/nestkernel/connection_manager.cpp index 7adaa036ba..a5560193ce 100644 --- a/nestkernel/connection_manager.cpp +++ b/nestkernel/connection_manager.cpp @@ -24,9 +24,9 @@ #include "connector_model.h" #include "network.h" #include "nest_time.h" -#include "connectiondatum.h" +#include "nest_datums.h" #include -// OpenMP + #ifdef _OPENMP #include #endif @@ -45,7 +45,7 @@ ConnectionManager::~ConnectionManager() for (std::vector::iterator i = pristine_prototypes_.begin(); i != pristine_prototypes_.end(); ++i) if (*i != 0) - delete *i; + delete *i; } void ConnectionManager::init(Dictionary* synapsedict) @@ -172,9 +172,6 @@ const Time ConnectionManager::get_min_delay() const if (*it != 0 && (*it)->get_num_connections() > 0) min_delay = std::min( min_delay, (*it)->get_min_delay() ); - if (min_delay == Time::pos_inf()) - min_delay = Time::get_resolution(); - return min_delay; } @@ -370,17 +367,16 @@ ArrayDatum ConnectionManager::get_connections(DictionaryDatum params) const { ArrayDatum connectome; - const Token source_t= params->lookup(names::source); - const Token target_t= params->lookup(names::target); - const Token syn_model_t=params->lookup(names::synapse_model); - const TokenArray *source_a=0; - const TokenArray *target_a=0; - + const Token& source_t = params->lookup(names::source); + const Token& target_t = params->lookup(names::target); + const Token& syn_model_t = params->lookup(names::synapse_model); + const TokenArray *source_a = 0; + const TokenArray *target_a = 0; if (not source_t.empty()) - source_a=dynamic_cast(source_t.datum()); + source_a=dynamic_cast(source_t.datum()); if (not target_t.empty()) - target_a=dynamic_cast(target_t.datum()); + target_a=dynamic_cast(target_t.datum()); size_t syn_id = 0; @@ -395,23 +391,23 @@ ArrayDatum ConnectionManager::get_connections(DictionaryDatum params) const // If not, we will iterate all. if (not syn_model_t.empty()) { - Name synmodel_name = getValue(syn_model_t); - const Token synmodel = synapsedict_->lookup(synmodel_name); - if (!synmodel.empty()) - syn_id = static_cast(synmodel); - else - throw UnknownModelName(synmodel_name.toString()); - get_connections(connectome, source_a, target_a, syn_id); + Name synmodel_name = getValue(syn_model_t); + const Token synmodel = synapsedict_->lookup(synmodel_name); + if (!synmodel.empty()) + syn_id = static_cast(synmodel); + else + throw UnknownModelName(synmodel_name.toString()); + get_connections(connectome, source_a, target_a, syn_id); } else { - for (syn_id = 0; syn_id < prototypes_.size(); ++syn_id) - { - ArrayDatum conn; - get_connections(conn, source_a, target_a, syn_id); - if (conn.size()>0) - connectome.push_back(new ArrayDatum(conn)); - } + for (syn_id = 0; syn_id < prototypes_.size(); ++syn_id) + { + ArrayDatum conn; + get_connections(conn, source_a, target_a, syn_id); + if (conn.size()>0) + connectome.push_back(new ArrayDatum(conn)); + } } return connectome; @@ -419,17 +415,17 @@ ArrayDatum ConnectionManager::get_connections(DictionaryDatum params) const void ConnectionManager::get_connections(ArrayDatum& connectome, TokenArray const *source, TokenArray const *target, size_t syn_id) const { - connectome.reserve(prototypes_[syn_id]->get_num_connections()); + connectome.reserve(prototypes_[syn_id]->get_num_connections()); - if ( source==0 and target == 0) - { + if (source==0 and target == 0) + { #ifdef _OPENMP #pragma omp parallel - { - thread t=omp_get_thread_num(); + { + thread t = omp_get_thread_num(); #else - for (thread t = 0; t < net_.get_num_threads(); ++t) - { + for (thread t = 0; t < net_.get_num_threads(); ++t) + { #endif ArrayDatum conns_in_thread; size_t num_connections_in_thread=0; @@ -466,11 +462,11 @@ void ConnectionManager::get_connections(ArrayDatum& connectome, TokenArray const connectome.reserve(prototypes_[syn_id]->get_num_connections()); #ifdef _OPENMP #pragma omp parallel - { - thread t=omp_get_thread_num(); + { + thread t=omp_get_thread_num(); #else - for (thread t = 0; t < net_.get_num_threads(); ++t) - { + for (thread t = 0; t < net_.get_num_threads(); ++t) + { #endif ArrayDatum conns_in_thread; size_t num_connections_in_thread=0; @@ -513,11 +509,11 @@ void ConnectionManager::get_connections(ArrayDatum& connectome, TokenArray const { #ifdef _OPENMP #pragma omp parallel - { - size_t t=omp_get_thread_num(); + { + size_t t=omp_get_thread_num(); #else - for (size_t t = 0; t < net_.get_num_threads(); ++t) - { + for (size_t t = 0; t < net_.get_num_threads(); ++t) + { #endif ArrayDatum conns_in_thread; size_t num_connections_in_thread=0; @@ -554,19 +550,18 @@ void ConnectionManager::get_connections(ArrayDatum& connectome, TokenArray const } } - if (conns_in_thread.size()>0) - { + if (conns_in_thread.size()>0) + { #ifdef _OPENMP #pragma omp critical #endif - connectome.append_move(conns_in_thread); - } - } - return; - } // else + connectome.append_move(conns_in_thread); + } + } + return; + } // else } - // Return connections to all targets void ConnectionManager::get_connections(ArrayDatum& connectome, index source, thread t, index syn_id) const { @@ -597,11 +592,28 @@ void ConnectionManager::connect(Node& s, Node& r, index s_gid, thread tid, Dicti num_conn_changed_since_counted_ = true; } + void ConnectionManager::connect(Node& s, Node& r, index s_gid, thread tid, double_t w, double_t d, DictionaryDatum& p, index syn) +{ + index syn_vec_index = validate_connector(tid, s_gid, syn); + connections_[tid].get(s_gid)[syn_vec_index].connector->register_connection(s, r, w, d, p); + num_conn_changed_since_counted_ = true; +} -// connect with a list of connection status dicts +/** + * Connect, using a dictionary with arrays. + * This variant of connect combines the functionalities of + * - connect + * - divergent_connect + * - convergent_connect + * The decision is based on the details of the dictionary entries source and target. + * If source and target are both either a GID or a list of GIDs with equal size, then source and target are connected one-to-one. + * If source is a gid and target is a list of GIDs then divergent_connect is used. + * If source is a list of GIDs and target is a GID, then convergent_connect is used. + * At this stage, the task of connect is to separate the dictionary into one for each thread and then to forward the + * connect call to the connectors who can then deal with the details of the connection. + */ bool ConnectionManager::connect(ArrayDatum& conns) { - std::string msg; // #ifdef _OPENMP // net_.message(SLIInterpreter::M_INFO, "ConnectionManager::Connect", msg); // #endif diff --git a/nestkernel/connection_manager.h b/nestkernel/connection_manager.h index 2f74988456..86bd690b54 100644 --- a/nestkernel/connection_manager.h +++ b/nestkernel/connection_manager.h @@ -166,6 +166,7 @@ class ConnectionManager void connect(Node& s, Node& r, index s_gid, thread tid, index syn); void connect(Node& s, Node& r, index s_gid, thread tid, double_t w, double_t d, index syn); void connect(Node& s, Node& r, index s_gid, thread tid, DictionaryDatum& p, index syn); + void connect(Node& s, Node& r, index s_gid, thread tid, double_t w, double_t d, DictionaryDatum& p, index syn); /** * Experimental bulk connector. See documentation in network.h diff --git a/nestkernel/connector.h b/nestkernel/connector.h index 891a5a702b..57b7475d28 100644 --- a/nestkernel/connector.h +++ b/nestkernel/connector.h @@ -46,6 +46,7 @@ class Connector virtual void register_connection(Node&, Node&) = 0; virtual void register_connection(Node&, Node&, double_t, double_t) = 0; virtual void register_connection(Node&, Node&, DictionaryDatum&) = 0; + virtual void register_connection(Node&, Node&, double_t, double_t, DictionaryDatum&) = 0; virtual std::vector* find_connections(DictionaryDatum) const = 0; /** * Return a list of all connections. diff --git a/nestkernel/connector_model.cpp b/nestkernel/connector_model.cpp index b180ac190e..3b10029a16 100644 --- a/nestkernel/connector_model.cpp +++ b/nestkernel/connector_model.cpp @@ -1,4 +1,3 @@ - /* * connector_model.cpp * diff --git a/nestkernel/dynamicloader.cpp b/nestkernel/dynamicloader.cpp index 790d282cd2..1c8b3e732f 100644 --- a/nestkernel/dynamicloader.cpp +++ b/nestkernel/dynamicloader.cpp @@ -97,7 +97,7 @@ namespace nest { // unload all loaded modules for (vecDynModules::iterator it = dyn_modules.begin(); - it != dyn_modules.end(); it++) + it != dyn_modules.end(); ++it) { if (it->handle != NULL) { lt_dlclose(it->handle); @@ -359,7 +359,7 @@ namespace nest { for (vecLinkedModules::iterator it = getLinkedModules().begin(); - it != getLinkedModules().end(); it++) + it != getLinkedModules().end(); ++it) { interpreter.message(SLIInterpreter::M_STATUS, "DynamicLoaderModule::initLinkedModules", "adding linked module"); diff --git a/nestkernel/event.cpp b/nestkernel/event.cpp index a0e4a16deb..5210317bdd 100644 --- a/nestkernel/event.cpp +++ b/nestkernel/event.cpp @@ -1,4 +1,3 @@ - /* * event.cpp * diff --git a/nestkernel/exceptions.cpp b/nestkernel/exceptions.cpp index 506187b8d9..8870680627 100644 --- a/nestkernel/exceptions.cpp +++ b/nestkernel/exceptions.cpp @@ -83,11 +83,6 @@ std::string nest::UnknownNode::message() return out.str(); } -std::string nest::MalformedAddress::message() -{ - return msg_; -} - std::string nest::NoThreadSiblingsAvailable::message() { std::ostringstream out; @@ -185,6 +180,16 @@ std::string nest::BadProperty::message() return msg_; } +std::string nest::BadParameter::message() +{ + return msg_; +} + +std::string nest::ChangeCommonPropsByIndividual::message() +{ + return msg_; +} + std::string nest::DimensionMismatch::message() { std::ostringstream out; @@ -333,7 +338,7 @@ std::string nest::GSLSolverFailure::message() std::string nest::NumericalInstability::message() { std::ostringstream msg; - msg << "NEST detected a numercial instability while " + msg << "NEST detected a numerical instability while " << "updating " << model_ << ". Try to reduce " << "gsl_error_tol for the model."; return msg.str(); diff --git a/nestkernel/exceptions.h b/nestkernel/exceptions.h index 036bd2be56..d331ee4695 100644 --- a/nestkernel/exceptions.h +++ b/nestkernel/exceptions.h @@ -1,5 +1,3 @@ -#ifndef EXCEPTIONS_H -#define EXCEPTIONS_H /* * exceptions.h * @@ -22,6 +20,9 @@ * */ +#ifndef EXCEPTIONS_H +#define EXCEPTIONS_H + #include "sliexceptions.h" #include "nest_time.h" #include "name.h" @@ -189,25 +190,6 @@ namespace nest { std::string message(); }; - /** - * Exception to be thrown if an incorrectly formed address is detected. - * @ingroup KernelExceptions - */ - - class MalformedAddress: public KernelException - { - std::string msg_; - public: - MalformedAddress(const std::string& msg) - : KernelException("MalformedAddress"), - msg_(msg) - {} - - ~MalformedAddress() throw () {} - - std::string message(); - }; - /** * Exception to be thrown if the specified * Node does not exist. @@ -449,6 +431,56 @@ namespace nest { std::string message(); }; + + /** + * Exception to be thrown if a parameter + * cannot be set. + * Thrown by Node::set_/get_property methods. + * @ingroup KernelExceptions + */ + class BadParameter: public KernelException + { + std::string msg_; + public: + //! @param detailed error message + BadParameter() + : KernelException("BadParameter"), + msg_() + {} + BadParameter(std::string msg) + : KernelException("BadParameter"), + msg_(msg) + {} + + ~BadParameter() throw () {} + + std::string message(); + }; + + /** + * Exception to be thrown if one tried to set the + * common properties via an individual synapse. + * Thrown by Node::set_/get_property methods. + * @ingroup KernelExceptions + */ + class ChangeCommonPropsByIndividual: public KernelException + { + std::string msg_; + public: + //! @param detailed error message + ChangeCommonPropsByIndividual() + : KernelException("ChangeCommonPropsByIndividual"), + msg_() + {} + ChangeCommonPropsByIndividual(std::string msg) + : KernelException("ChangeCommonPropsByIndividual"), + msg_(msg) + {} + + ~ChangeCommonPropsByIndividual() throw () {} + + std::string message(); + }; /** * Exception to be thrown if the dimensions diff --git a/nestkernel/generic_connector.h b/nestkernel/generic_connector.h index 3d958c72d0..54a586014d 100644 --- a/nestkernel/generic_connector.h +++ b/nestkernel/generic_connector.h @@ -34,7 +34,7 @@ #include "spikecounter.h" #include "nest_names.h" -#include "connectiondatum.h" +#include "nest_datums.h" namespace nest { /** @@ -92,6 +92,12 @@ class GenericConnectorBase : public Connector * Use given dictionary for parameters. */ void register_connection(Node&, Node&, DictionaryDatum&); + + /** + * Register a new connection at the sender side. + * Use given weight, delay and dictionary for parameters. + */ + void register_connection(Node&, Node&, double_t, double_t, DictionaryDatum&); /** * Register a new connection at the sender side. @@ -252,6 +258,34 @@ void GenericConnectorBase< ConnectionT, CommonPropertiesT, ConnectorModelT >::re register_connection(s, r, cn, receptor_type); } +template< typename ConnectionT, typename CommonPropertiesT, typename ConnectorModelT > + void GenericConnectorBase< ConnectionT, CommonPropertiesT, ConnectorModelT >::register_connection(Node& s, Node& r, double_t w, double_t d, DictionaryDatum& p) +{ + // We have to convert the delay in ms to a Time object then to steps and back the ms again + // in order to get the value in ms which can be represented with an integer number of steps + // in the currently chosen Time representation. + // See also bug #217, MH 08-04-23 + if ( !connector_model_.check_delay( Time(Time::step(Time(Time::ms(d)).get_steps())).get_ms() ) ) + throw BadDelay(d); + + // create a new instance of the default connection + ConnectionT cn = ConnectionT( connector_model_.get_default_connection() ); + // TODO: check wether dictionary p is empty, if so skip the following line + cn.set_status(p, connector_model_); + cn.set_weight(w); + cn.set_delay(d); + + port receptor_type = connector_model_.get_receptor_type(); + +#ifdef HAVE_MUSIC + // We allow music_channel as alias for receptor_type during connection setup + updateValue(p, names::music_channel, receptor_type); +#endif + updateValue(p, names::receptor_type, receptor_type); + + register_connection(s, r, cn, receptor_type); +} + template< typename ConnectionT, typename CommonPropertiesT, typename ConnectorModelT > inline void GenericConnectorBase< ConnectionT, CommonPropertiesT, ConnectorModelT >::register_connection(Node& s, Node& r, ConnectionT &cn, port receptor_type) diff --git a/nestkernel/generic_connector_model.h b/nestkernel/generic_connector_model.h index afb6f4dfd6..fa47f8c2e9 100644 --- a/nestkernel/generic_connector_model.h +++ b/nestkernel/generic_connector_model.h @@ -261,7 +261,16 @@ void GenericConnectorModelBase< ConnectionT, CommonPropertiesT, ConnectorT >::se Time max_delay_tmp = max_delay_; common_props_.set_status(d, *this); - defaults_.set_status(d, *this); + + try { + defaults_.set_status(d, *this); + } + catch (ChangeCommonPropsByIndividual e) + { + // ignore this exception, because + // it is meaningless here, since we are actually changing + // the properties of the default object, not an individual synapse + } // restore min_delay_, max_delay_ min_delay_ = min_delay_tmp; diff --git a/nestkernel/genericmodel.h b/nestkernel/genericmodel.h index 28c5c44c0b..ad0100a488 100644 --- a/nestkernel/genericmodel.h +++ b/nestkernel/genericmodel.h @@ -1,5 +1,3 @@ -#ifndef GENERICMODEL_H -#define GENERICMODEL_H /* * genericmodel.h * @@ -22,6 +20,9 @@ * */ +#ifndef GENERICMODEL_H +#define GENERICMODEL_H + #include "model.h" #include "dynmodule.h" #include @@ -55,6 +56,7 @@ namespace nest Model* clone(const std::string&) const; bool has_proxies(); + bool potential_global_receiver(); bool one_node_per_process(); bool is_off_grid(); /** @@ -151,6 +153,13 @@ namespace nest { return proto_.has_proxies(); } + + template + inline + bool GenericModel::potential_global_receiver() + { + return proto_.potential_global_receiver(); + } template inline diff --git a/nestkernel/gid_collection.cpp b/nestkernel/gid_collection.cpp new file mode 100644 index 0000000000..5a44e00348 --- /dev/null +++ b/nestkernel/gid_collection.cpp @@ -0,0 +1,61 @@ +/* + * gid_collection.cpp + * + * This file is part of NEST. + * + * Copyright (C) 2004 The NEST Initiative + * + * NEST 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 2 of the License, or + * (at your option) any later version. + * + * NEST 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 NEST. If not, see . + * + */ + +#include "gid_collection.h" + +#include + +namespace nest { + + GIDCollection::GIDCollection(index first, index last) + : is_range_(true) + { + gid_range_.first = first; + gid_range_.second = last; + } + + GIDCollection::GIDCollection(IntVectorDatum gids) + : is_range_(false) + { + gid_array_.resize(gids->size()); + std::copy(gids->begin(), gids->end(), gid_array_.begin()); + } + + GIDCollection::GIDCollection(TokenArray gids) + : is_range_(false) + { + gid_array_.resize(gids.size()); + for (size_t i = 0; i < gids.size(); ++i) + gid_array_[i] = gids[i]; + } + + void GIDCollection::print_me(std::ostream& out) const + { + out << "[[is_range=" << is_range_ << ",size=" << size() << ","; + if (is_range_) + out << "(" << gid_range_.first << ".." << gid_range_.second << ")"; + else + out << "(" << gid_array_[0] << ".." << gid_array_[gid_array_.size()-1] << ")"; + out << "]]"; + } + +} // namespace nest diff --git a/nestkernel/gid_collection.h b/nestkernel/gid_collection.h new file mode 100644 index 0000000000..8fe291f445 --- /dev/null +++ b/nestkernel/gid_collection.h @@ -0,0 +1,135 @@ +/* + * gid_collection.h + * + * This file is part of NEST. + * + * Copyright (C) 2004 The NEST Initiative + * + * NEST 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 2 of the License, or + * (at your option) any later version. + * + * NEST 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 NEST. If not, see . + * + */ + +#ifndef GID_COLLECTION_H +#define GID_COLLECTION_H + +#include +#include +#include +#include + +#include "nest.h" +#include "tokenarray.h" +#include "arraydatum.h" + +namespace nest { + + class GIDCollection { + + std::vector gid_array_; + std::pair gid_range_; + bool is_range_; + + public: + + class const_iterator { + friend class GIDCollection; + const_iterator(const GIDCollection* gc, size_t offset) : gc_(gc), offset_(offset) {} + const GIDCollection* gc_; + size_t offset_; + public: + index operator*() const; + const const_iterator& operator++(); + bool operator!=(const const_iterator& rhs) const; + }; + + GIDCollection() {} + GIDCollection(index first, index last); + GIDCollection(IntVectorDatum gids); + GIDCollection(TokenArray gids); + + void print_me(std::ostream& out) const; + + index operator[] (const size_t pos) const; + bool operator==(const GIDCollection& rhs) const; + + const_iterator begin() const; + const_iterator end() const; + + size_t size() const; + }; + + inline + index GIDCollection::const_iterator::operator*() const + { + return (*gc_)[offset_]; + } + + inline + const GIDCollection::const_iterator& GIDCollection::const_iterator::operator++() + { + ++offset_; + return *this; + } + + inline + bool GIDCollection::const_iterator::operator!=(const GIDCollection::const_iterator& rhs) const + { + return offset_ != rhs.offset_; + } + + inline + index GIDCollection::operator[] (const size_t pos) const + { + if ((is_range_ && pos + gid_range_.first > gid_range_.second) || (!is_range_ && pos >= gid_array_.size())) + throw std::out_of_range("pos points outside of the GIDCollection"); + + if (is_range_) + return gid_range_.first + pos; + else + return gid_array_[pos]; + } + + inline + bool GIDCollection::operator==(const GIDCollection& rhs) const + { + if (is_range_) + return gid_range_ == rhs.gid_range_; + else + return gid_array_ == rhs.gid_array_; + } + + inline + GIDCollection::const_iterator GIDCollection::begin() const + { + return const_iterator(this, 0); + } + + inline + GIDCollection::const_iterator GIDCollection::end() const + { + return const_iterator(this, size()); + } + + inline + size_t GIDCollection::size() const + { + if (is_range_) + return gid_range_.second - gid_range_.first + 1; + else + return gid_array_.size(); + } + +} // namespace nest + +#endif /* #ifndef GID_COLLECTION_H */ diff --git a/nestkernel/model.h b/nestkernel/model.h index b5a13a4c90..33994bc016 100644 --- a/nestkernel/model.h +++ b/nestkernel/model.h @@ -127,6 +127,7 @@ namespace nest size_t mem_capacity(); virtual bool has_proxies()=0; + virtual bool potential_global_receiver()=0; virtual bool one_node_per_process()=0; virtual bool is_off_grid()=0; diff --git a/nestkernel/modelrangemanager.cpp b/nestkernel/modelrangemanager.cpp index 4398505baf..66fd34c2ff 100644 --- a/nestkernel/modelrangemanager.cpp +++ b/nestkernel/modelrangemanager.cpp @@ -81,7 +81,7 @@ bool Modelrangemanager::model_in_use(index i) const { bool found = false; - for (std::vector::const_iterator it = modelranges_.begin(); it != modelranges_.end(); it++) + for (std::vector::const_iterator it = modelranges_.begin(); it != modelranges_.end(); ++it) if ( it->get_model_id() == i ) { found = true; @@ -99,9 +99,9 @@ void Modelrangemanager::clear() const modelrange& Modelrangemanager::get_range(index gid) const { if (!is_in_range(gid)) - throw UnknownNode(gid); - - for (std::vector::const_iterator it = modelranges_.begin(); it != modelranges_.end(); it++) + throw UnknownNode(gid); + + for (std::vector::const_iterator it = modelranges_.begin(); it != modelranges_.end(); ++it) if ( it->is_in_range(gid) ) return (*it); diff --git a/nestkernel/music_event_handler.cpp b/nestkernel/music_event_handler.cpp index 24d1122747..4745535a16 100644 --- a/nestkernel/music_event_handler.cpp +++ b/nestkernel/music_event_handler.cpp @@ -36,15 +36,17 @@ namespace nest music_perm_ind_(0), published_(false), portname_(""), - acceptable_latency_(0.0) + acceptable_latency_(0.0), + max_buffered_(-1) {} - MusicEventHandler::MusicEventHandler(std::string portname, double acceptable_latency, Network* net) + MusicEventHandler::MusicEventHandler(std::string portname, double acceptable_latency, int max_buffered, Network* net) : music_port_(0), music_perm_ind_(0), published_(false), portname_(portname), acceptable_latency_(acceptable_latency), + max_buffered_(max_buffered), net_(net) {} @@ -100,10 +102,16 @@ namespace nest // create the permutation index mapping music_perm_ind_ = new MUSIC::PermutationIndex(&indexmap_.front(), indexmap_.size()); // map the port - music_port_->map(music_perm_ind_, this, acceptable_latency); - - std::string msg = String::compose("Mapping MUSIC input port '%1' with width=%2 and acceptable latency=%3 ms.", - portname_, music_port_width, acceptable_latency_); + if (max_buffered_ >= 0) + music_port_->map(music_perm_ind_, this, acceptable_latency, max_buffered_); + else + music_port_->map(music_perm_ind_, this, acceptable_latency); + + std::string msg = String::compose("Mapping MUSIC input port '%1' with width=%2 , acceptable latency=%3 ms", + portname_, music_port_width, acceptable_latency); + if (max_buffered_ > 0) + msg += String::compose(" and max buffered=%1 ticks", max_buffered_); + msg += "."; net_->message(SLIInterpreter::M_INFO, "MusicEventHandler::publish_port()", msg.c_str()); } } diff --git a/nestkernel/music_event_handler.h b/nestkernel/music_event_handler.h index 780b451e7a..faeb3e0f71 100644 --- a/nestkernel/music_event_handler.h +++ b/nestkernel/music_event_handler.h @@ -44,7 +44,7 @@ class MusicEventHandler : public MUSIC::EventHandlerGlobalIndex { public: MusicEventHandler(); - MusicEventHandler(std::string portname, double acceptable_latency, Network* net); + MusicEventHandler(std::string portname, double acceptable_latency, int max_buffered, Network* net); virtual ~MusicEventHandler(); @@ -81,6 +81,7 @@ class MusicEventHandler : public MUSIC::EventHandlerGlobalIndex std::vector channelmap_; //!< Maps channel number to music_event_in_proxy std::vector indexmap_; //!< Maps local index to global MUSIC index (channel) double acceptable_latency_; //!< The acceptable latency of the port in ms + int max_buffered_; Network* net_; //!< Pointer to global network driver. /** diff --git a/nestkernel/nest.h b/nestkernel/nest.h index 4d98b27a95..decfe18775 100644 --- a/nestkernel/nest.h +++ b/nestkernel/nest.h @@ -1,5 +1,3 @@ -#ifndef NEST_H -#define NEST_H /* * nest.h * @@ -22,6 +20,9 @@ * */ +#ifndef NEST_H +#define NEST_H + #include #include #include "config.h" diff --git a/nestkernel/connectiondatum.cpp b/nestkernel/nest_datums.cpp similarity index 51% rename from nestkernel/connectiondatum.cpp rename to nestkernel/nest_datums.cpp index 818f75165d..8d3dc7f07a 100644 --- a/nestkernel/connectiondatum.cpp +++ b/nestkernel/nest_datums.cpp @@ -1,5 +1,5 @@ /* - * connectiondatum.cpp + * nest_datums.cpp * * This file is part of NEST. * @@ -20,29 +20,20 @@ * */ -#include "connectiondatum.h" -#include "datumconverter.h" +#include "nest_datums.h" -#include "aggregatedatum_impl.h" - -// explicit instantiation +// explicit instantiations template class AggregateDatum; +template class AggregateDatum; -template<> sli::pool - AggregateDatum::memory( - sizeof(nest::ConnectionID),10000,1); - - -template<> -void AggregateDatum::print(std::ostream &out) const -{ - out << "/connectiontype"; -} +// instantiate memory management pool +template<> sli::pool ConnectionDatum::memory(sizeof(nest::ConnectionID),10000,1); +template<> sli::pool GIDCollectionDatum::memory(sizeof(nest::GIDCollection),10000,1); -template<> -void AggregateDatum::pprint(std::ostream &out) const -{ - out << "<" << source_gid_ << ',' << target_gid_ << ',' - << target_thread_ << ',' << synapse_modelid_ << ',' << port_ << ">"; -} +// simple type printing +template<> void ConnectionDatum::print(std::ostream &out) const { out << "/connectiontype"; } +template<> void GIDCollectionDatum::print(std::ostream &out) const { out << "/gidcollectiontype"; } +// printing of the objects +template<> void ConnectionDatum::pprint(std::ostream &out) const { print_me(out); } +template<> void GIDCollectionDatum::pprint(std::ostream &out) const { print_me(out); } diff --git a/nestkernel/connectiondatum.h b/nestkernel/nest_datums.h similarity index 63% rename from nestkernel/connectiondatum.h rename to nestkernel/nest_datums.h index ca537c85b5..bb6a2a6335 100644 --- a/nestkernel/connectiondatum.h +++ b/nestkernel/nest_datums.h @@ -1,5 +1,5 @@ /* - * connectiondatum.h + * nest_datums.h * * This file is part of NEST. * @@ -20,28 +20,31 @@ * */ -#ifndef CONNECTIONDATUM_H -#define CONNECTIONDATUM_H +#ifndef NEST_DATUMS_H +#define NEST_DATUMS_H /** * SLI Datum types related to the NEST kernel. */ #include "nestmodule.h" -#include "connection_id.h" #include "aggregatedatum.h" +#include "connection_id.h" +#include "gid_collection.h" + +typedef AggregateDatum ConnectionDatum; +typedef AggregateDatum GIDCollectionDatum; #ifndef HAVE_STATIC_TEMPLATE_DECLARATION_FAILS -template<> -sli::pool AggregateDatum::memory; +template<> sli::pool ConnectionDatum::memory; +template<> sli::pool GIDCollectionDatum::memory; #endif -template<> -void AggregateDatum::print(std::ostream &) const; -template<> -void AggregateDatum::pprint(std::ostream &) const; -typedef AggregateDatum ConnectionDatum; +template<> void ConnectionDatum::print(std::ostream &) const; +template<> void GIDCollectionDatum::print(std::ostream &) const; +template<> void ConnectionDatum::pprint(std::ostream &) const; +template<> void GIDCollectionDatum::pprint(std::ostream &) const; -#endif +#endif /* #ifndef NEST_DATUMS_H */ diff --git a/nestkernel/nest_names.cpp b/nestkernel/nest_names.cpp index 58b6840771..775208d802 100644 --- a/nestkernel/nest_names.cpp +++ b/nestkernel/nest_names.cpp @@ -37,6 +37,7 @@ namespace nest const Name C_m("C_m"); const Name tau_m("tau_m"); const Name tau_syn("tau_syn"); + const Name taus_syn("taus_syn"); const Name tau_syn_ex("tau_syn_ex"); const Name tau_syn_in("tau_syn_in"); const Name t_ref("t_ref"); @@ -62,6 +63,10 @@ namespace nest const Name E_K("E_K"); const Name in_spikes("in_spikes"); const Name ex_spikes("ex_spikes"); + const Name weighted_spikes_in("weighted_spikes_in"); + const Name weighted_spikes_ex("weighted_spikes_ex"); + const Name input_currents_in("input_currents_in"); + const Name input_currents_ex("input_currents_ex"); const Name error("error"); // Related to ArchivingNode @@ -100,6 +105,8 @@ namespace nest const Name w("w"); const Name Delta_T("Delta_T"); const Name tau_w("tau_w"); + const Name HMIN("HMIN"); //!< Smallest integration step for adaptive stepsize + const Name MAXERR("MAXERR"); //!< Largest permissible error for adaptive stepsize // Additional parameters for Izhikevich 2003 const Name c("c"); @@ -111,12 +118,17 @@ namespace nest const Name dU("U"); //!< Unit increment of the utilization for a facilitating synapse [0...1] const Name u("u"); //!< probability of release [0...1] const Name x("x"); //!< current scaling factor of the synaptic weight [0...1] + const Name p("p"); //!< current release probability + const Name n("n"); const Name tau_rec("tau_rec"); //!< time constant for recovery (ms) const Name tau_fac("tau_fac"); //!< facilitation time constant (ms) const Name dUs("Us"); //!< Unit increment of the utilization for a facilitating synapse [0...1] const Name us("us"); //!< probability of release [0...1] const Name xs("xs"); //!< current scaling factor of the synaptic weight [0...1] + const Name ps("ps"); //!< current release probability + const Name ns("ns"); + const Name as("as"); const Name tau_recs("tau_recs"); //!< time constant for recovery (ms) const Name tau_facs("tau_facs"); //!< facilitation time constant (ms) @@ -140,6 +152,7 @@ namespace nest const Name epoch("epoch"); const Name success("success"); const Name with_noise("with_noise"); + const Name weight_std("weight_std"); // Other Adaptation @@ -189,6 +202,22 @@ namespace nest const Name S("S"); // Binary state (output) of neuron const Name h("h"); // Summed input to a neuron + + const Name I_syn("I_syn"); //!< following parameters used for iaflossless_count_exp + const Name pot_spikes("pot_spikes"); + const Name dhaene_quick1("dhaene_quick1"); + const Name dhaene_quick2("dhaene_quick2"); + const Name dhaene_tmax_lt_t1("dhaene_tmax_lt_t1"); + const Name dhaene_max_geq_V_th("dhaene_max_geq_V_th"); + const Name dhaene_det_spikes("dhaene_det_spikes"); + const Name eq7("eq7"); + const Name eq9("eq9"); + const Name eqs7and9("eqs7and9"); + const Name lin_left_geq_V_th("lin_left_geq_V_th"); + const Name lin_max_geq_V_th("lin_max_geq_V_th"); + const Name eq13("eq13"); + const Name eq12("eq12"); + // Specific to iaf_chxk_2008 neuron const Name g_ahp("g_ahp"); const Name tau_ahp("tau_ahp"); @@ -205,6 +234,14 @@ namespace nest const Name I_syn_ex("I_syn_ex"); // Total excitatory synaptic current const Name I_syn_in("I_syn_in"); // Total inhibitory synaptic current + // Specific to population point process model (pp_pop_psc_delta) + const Name N("N"); + const Name rho_0("rho_0"); + const Name delta_u("delta_u"); + const Name len_kernel("len_kernel"); + const Name taus_eta("taus_eta"); + const Name vals_eta("vals_eta"); + // Specific to GSL integration const Name gsl_error_tol("gsl_error_tol"); // GSL integrator tolerance @@ -213,14 +250,22 @@ namespace nest const Name mother_rng("mother_rng"); const Name p_copy("p_copy"); - // Specific to correlation detector + // Specific to correlation and correlomatrix detector const Name delta_tau("delta_tau"); const Name tau_max("tau_max"); - const Name histogram("histogram"); - const Name count_histogram("count_histogram"); const Name Tstart("Tstart"); const Name Tstop("Tstop"); + // Specific to correlation detector + const Name histogram("histogram"); + const Name histogram_correction("histogram_correction"); + const Name count_histogram("count_histogram"); + + // Specific to correlomatrix detector + const Name N_channels("N_channels"); + const Name covariance("covariance"); + const Name count_covariance("count_covariance"); + const Name origin("origin"); const Name start("start"); const Name stop("stop"); @@ -299,10 +344,14 @@ namespace nest const Name dead_time("dead_time"); const Name gamma_shape("gamma_shape"); + // Specific to iaf_psc_exp_multisynapse and iaf_psc_alpha_multisynapse + const Name has_connections("has_connections"); + // Miscellaneous parameters const Name label("label"); const Name mean("mean"); const Name std("std"); + const Name std_mod("std_mod"); const Name rms("rms"); const Name dt("dt"); const Name offset("offset"); @@ -330,12 +379,18 @@ namespace nest const Name theta("theta"); // Node types - const Name type("type"); + const Name type("node_type"); const Name structure("structure"); const Name neuron("neuron"); const Name stimulator("stimulator"); const Name recorder("recorder"); const Name synapse("synapse"); const Name other("other"); + + // connectivity-related + const Name rule("rule"); + const Name autapses("autapses"); + const Name multapses("multapses"); + const Name distribution("distribution"); } } diff --git a/nestkernel/nest_names.h b/nestkernel/nest_names.h index 377bc8d19a..512566a96b 100644 --- a/nestkernel/nest_names.h +++ b/nestkernel/nest_names.h @@ -1,5 +1,3 @@ -#ifndef NEST_NAMES_H -#define NEST_NAMES_H /* * nest_names.h * @@ -22,6 +20,9 @@ * */ +#ifndef NEST_NAMES_H +#define NEST_NAMES_H + #include "name.h" namespace nest @@ -37,45 +38,66 @@ namespace nest namespace names { // Neuron parameters - extern const Name V_m; //!< Membrane potential - extern const Name V_min; //!< Absolute lower value for the membrane potential - extern const Name E_L; //!< Resting potential - extern const Name I_e; //!< Input current - extern const Name I_L; //!< Leak current - extern const Name V_th; //!< Threshold - extern const Name V_reset; //!< Reset potential - extern const Name c_m; //!< Capacity or specific capacitance - extern const Name C_m; //!< Membrane capacitance - extern const Name tau_m; //!< Membrane time constant - extern const Name tau_syn; //!< Synapse time constant - extern const Name tau_syn_ex; //!< Excitatory synaptic time constant - extern const Name tau_syn_in; //!< Inhibitory synaptic time constant - extern const Name t_ref; //!< Refractory period - extern const Name t_ref_abs; //!< Absolute refractory period - extern const Name t_ref_tot; //!< Total refractory period - extern const Name t_ref_remaining; //!< Time remaining till end of refractory state - extern const Name t_spike; //!< Time of last spike - extern const Name t_origin; //!< Origin of a time-slice - extern const Name t_lag; //!< Lag within a time slice - extern const Name E_ex; //!< Excitatory reversal potential - extern const Name E_in; //!< Inhibitory reversal potential - extern const Name g; //!< Conductance - extern const Name g_L; //!< Leak conductance - extern const Name g_ex; //!< Excitatory conductance - extern const Name dg_ex; //!< Derivative of the excitatory conductance - extern const Name g_in; //!< inhibitory conductance - extern const Name dg_in; //!< Derivative of the inhibitory conductance - extern const Name g_Na; //!< Sodium conductance - extern const Name E_ex; //!< Excitatory reversal potential - extern const Name E_in; //!< Inhibitory reversal potential - extern const Name I_ex; //!< Excitatory synaptic input current - extern const Name I_in; //!< Inhibitory synaptic input current - extern const Name E_Na; //!< Sodium reversal potential - extern const Name g_K; //!< Potassium conductance - extern const Name E_K; //!< Potassium reversal potential - extern const Name in_spikes; //!< Number of arriving inhibitory spikes - extern const Name ex_spikes; //!< Number of arriving excitatory spikes - extern const Name error; //!< Indicates an error in a neuron + extern const Name V_m; //!< Membrane potential + extern const Name V_min; //!< Absolute lower value for the membrane potential + extern const Name E_L; //!< Resting potential + extern const Name I_e; //!< Input current + extern const Name I_L; //!< Leak current + extern const Name V_th; //!< Threshold + extern const Name V_reset; //!< Reset potential + extern const Name c_m; //!< Capacity or specific capacitance + extern const Name C_m; //!< Membrane capacitance + extern const Name tau_m; //!< Membrane time constant + extern const Name tau_syn; //!< Synapse time constant + extern const Name taus_syn; //!< Synapse time constants (array) + extern const Name tau_syn_ex; //!< Excitatory synaptic time constant + extern const Name tau_syn_in; //!< Inhibitory synaptic time constant + extern const Name t_ref; //!< Refractory period + extern const Name t_ref_abs; //!< Absolute refractory period + extern const Name t_ref_tot; //!< Total refractory period + extern const Name t_ref_remaining; //!< Time remaining till end of refractory state + extern const Name t_spike; //!< Time of last spike + extern const Name t_origin; //!< Origin of a time-slice + extern const Name t_lag; //!< Lag within a time slice + extern const Name E_ex; //!< Excitatory reversal potential + extern const Name E_in; //!< Inhibitory reversal potential + extern const Name g; //!< Conductance + extern const Name g_L; //!< Leak conductance + extern const Name g_ex; //!< Excitatory conductance + extern const Name dg_ex; //!< Derivative of the excitatory conductance + extern const Name g_in; //!< inhibitory conductance + extern const Name dg_in; //!< Derivative of the inhibitory conductance + extern const Name g_Na; //!< Sodium conductance + extern const Name E_ex; //!< Excitatory reversal potential + extern const Name E_in; //!< Inhibitory reversal potential + extern const Name I_ex; //!< Excitatory synaptic input current + extern const Name I_in; //!< Inhibitory synaptic input current + extern const Name E_Na; //!< Sodium reversal potential + extern const Name g_K; //!< Potassium conductance + extern const Name E_K; //!< Potassium reversal potential + extern const Name in_spikes; //!< Number of arriving inhibitory spikes + extern const Name ex_spikes; //!< Number of arriving excitatory spikes + extern const Name weighted_spikes_in; //!< Weighted incoming inhibitory spikes + extern const Name weighted_spikes_ex; //!< Weighted incoming excitatory spikes + extern const Name input_currents_in; //!< Incoming inhibitory currents + extern const Name input_currents_ex; //!< Incoming excitatory currents + + extern const Name I_syn; //!< following parameters used for iaflossless_count_exp + extern const Name pot_spikes; + extern const Name dhaene_quick1; + extern const Name dhaene_quick2; + extern const Name dhaene_tmax_lt_t1; + extern const Name dhaene_max_geq_V_th; + extern const Name dhaene_det_spikes; + extern const Name eq7; + extern const Name eq9; + extern const Name eqs7and9; + extern const Name lin_left_geq_V_th; + extern const Name lin_max_geq_V_th; + extern const Name eq13; + extern const Name eq12; + + extern const Name error; //!< Indicates an error in a neuron // Related to ArchivingNode extern const Name tau_minus; @@ -106,13 +128,15 @@ namespace nest extern const Name V_th_alpha_1; extern const Name V_th_alpha_2; - // Specific to Brette & Gerstner 2005 + // Specific to Brette & Gerstner 2005 (aeif_cond-*) extern const Name V_peak; //!< Spike detection threshold (Brette & Gerstner 2005) extern const Name a; extern const Name b; extern const Name w; extern const Name Delta_T; extern const Name tau_w; + extern const Name HMIN; //!< Smallest integration step for adaptive stepsize + extern const Name MAXERR; //!< Largest permissible error for adaptive stepsize // Specific to Izhikevich 2003 extern const Name c; @@ -123,6 +147,8 @@ namespace nest // Tsodyks2_connection extern const Name dU; //!< Unit increment of the utilization for a facilitating synapse [0...1] extern const Name u; //!< probability of release [0...1] + extern const Name p; //!< current release probability + extern const Name n; //!< Number of synaptic release sites (int >=0) extern const Name x; //!< current scaling factor of the synaptic weight [0...1] extern const Name tau_rec; //!< time constant for recovery (ms) extern const Name tau_fac; //!< facilitation time constant (ms) @@ -144,6 +170,7 @@ namespace nest extern const Name F_lower; extern const Name F_mean; extern const Name F_std; + extern const Name weight_std; //!< Standard deviation/mean of noisy synapse. extern const Name epoch; extern const Name success; extern const Name with_noise; @@ -154,6 +181,9 @@ namespace nest extern const Name dUs; //!< Unit increment of the utilization for a facilitating synapse [0...1] extern const Name us; //!< probability of release [0...1] extern const Name xs; //!< current scaling factor of the synaptic weight [0...1] + extern const Name ps; //!< current release probability [0...1] + extern const Name ns; //!< Number of release sites + extern const Name as; //!< Number of available release sites extern const Name tau_recs; //!< time constant for recovery (ms) extern const Name tau_facs; //!< facilitation time constant (ms) @@ -178,14 +208,22 @@ namespace nest extern const Name mother_rng; extern const Name p_copy; - // Specific to correlation_detector + // Specific to correlation_and correlomatrix detector extern const Name delta_tau; extern const Name tau_max; - extern const Name histogram; - extern const Name count_histogram; extern const Name Tstart; extern const Name Tstop; + // Specific to correlation_detector + extern const Name histogram; + extern const Name histogram_correction; + extern const Name count_histogram; + + // Specific to correlomatrix_detector + extern const Name N_channels; + extern const Name covariance; + extern const Name count_covariance; + // Specific to current homeostasis extern const Name I_total; //<- Total current extern const Name I_adapt; //<- Goal of current homeostasis @@ -234,6 +272,14 @@ namespace nest extern const Name I_syn_ex; // Total excitatory synaptic current extern const Name I_syn_in; // Total inhibitory synaptic current + // Specific to population point process model (pp_pop_psc_delta) + extern const Name N; + extern const Name rho_0; + extern const Name delta_u; + extern const Name len_kernel; + extern const Name taus_eta; + extern const Name vals_eta; + // Names relating to GSL integration extern const Name gsl_error_tol; // GSL integrator tolerance @@ -320,10 +366,14 @@ namespace nest extern const Name dead_time; extern const Name gamma_shape; + // Specific to iaf_psc_exp_multisynapse and iaf_psc_alpha_multisynapse + extern const Name has_connections; + // Miscellaneous parameters extern const Name label; extern const Name mean; extern const Name std; + extern const Name std_mod; extern const Name rms; // Root mean square extern const Name dt; extern const Name offset; @@ -359,6 +409,12 @@ namespace nest extern const Name recorder; extern const Name synapse; extern const Name other; + + // Connectivity-related + extern const Name rule; + extern const Name autapses; + extern const Name multapses; + extern const Name distribution; } } diff --git a/nestkernel/nest_timeconverter.h b/nestkernel/nest_timeconverter.h index 2d9d824f27..e0640fc2d2 100644 --- a/nestkernel/nest_timeconverter.h +++ b/nestkernel/nest_timeconverter.h @@ -1,4 +1,3 @@ - /* * nest_timeconverter.h * diff --git a/nestkernel/nestmodule.cpp b/nestkernel/nestmodule.cpp index fa8f4e6bf1..83feb234a4 100644 --- a/nestkernel/nestmodule.cpp +++ b/nestkernel/nestmodule.cpp @@ -25,7 +25,9 @@ #include #include #include "nest.h" +#include "nest_datums.h" #include "network.h" +#include "network_impl.h" #include "nodelist.h" #include "interpret.h" #include "node.h" @@ -38,10 +40,10 @@ #include "tokenutils.h" #include "sliexceptions.h" #include "random_datums.h" -#include "connectiondatum.h" #include "communicator.h" #include "communicator_impl.h" #include "genericmodel.h" +#include "conn_builder.h" #if defined IS_BLUEGENE_P || defined IS_BLUEGENE_Q extern "C" @@ -64,6 +66,7 @@ extern int SLIsignalflag; namespace nest { SLIType NestModule::ConnectionType; + SLIType NestModule::GIDCollectionType; Network* NestModule::net_ = 0; @@ -84,6 +87,7 @@ namespace nest // dynamicloadermodule also needs it ConnectionType.deletetypename(); + GIDCollectionType.deletetypename(); } void NestModule::register_network(Network& net) @@ -101,8 +105,7 @@ namespace nest const std::string NestModule::commandstring(void) const { - return std::string("/nest-init /C++ ($Revision: 10474 $) provide-component " - "/nest-init /SLI (1.21) require-component"); + return std::string("(nest-init) run"); } @@ -443,15 +446,21 @@ namespace nest else throw UnknownModelName(modelname.toString()); + std::string missed; if (!dict->all_accessed(missed)) { + if (get_network().dict_miss_is_error()) + { + throw UnaccessedDictionaryEntry(missed); + } else get_network().message(SLIInterpreter::M_WARNING, "SetDefaults", ("Unread dictionary entries: " + missed).c_str()); } + i->OStack.pop(2); i->EStack.pop(); } @@ -493,9 +502,6 @@ namespace nest i->EStack.pop(); } - // params: params - - // params: params void NestModule::GetConnections_DFunction::execute(SLIInterpreter *i) const { i->assert_stack_load(1); @@ -505,8 +511,17 @@ namespace nest dict->clear_access_flags(); ArrayDatum array = get_network().get_connections(dict); + std::string missed; - + if ( !dict->all_accessed(missed) ) + { + if ( get_network().dict_miss_is_error() ) + throw UnaccessedDictionaryEntry(missed); + else + get_network().message(SLIInterpreter::M_WARNING, "GetConnections", + ("Unread dictionary entries: " + missed).c_str()); + } + i->OStack.pop(); i->OStack.push(array); i->EStack.pop(); @@ -832,7 +847,7 @@ namespace nest i->EStack.pop(); } - // Connect for gid gid + // Connect for gid gid syn_model // See lib/sli/nest-init.sli for details void NestModule::Connect_i_i_lFunction::execute(SLIInterpreter *i) const { @@ -847,25 +862,19 @@ namespace nest throw UnknownSynapseType(synmodel_name.toString()); const index synmodel_id = static_cast(synmodel); - get_network().connect(source, target, synmodel_id); + // check whether the target is on this process + if (get_network().is_local_gid(target)) + { + Node* const target_node = get_network().get_node(target); + const thread target_thread = target_node->get_thread(); + get_network().connect(source, target, target_node, target_thread, synmodel_id); + } i->OStack.pop(3); i->EStack.pop(); } - void NestModule::Connect_i_i_iFunction::execute(SLIInterpreter *i) const - { - long &source = static_cast(i->OStack.pick(2).datum())->get(); - long &target = static_cast(i->OStack.pick(1).datum())->get(); - long &synmodel_id = static_cast(i->OStack.pick(0).datum())->get(); - - get_network().connect(source, target, synmodel_id); - - i->OStack.pop(3); - i->EStack.pop(); - } - - // Connect for gid gid weight delay + // Connect for gid gid weight delay syn_model // See lib/sli/nest-init.sli for details void NestModule::Connect_i_i_d_d_lFunction::execute(SLIInterpreter *i) const { @@ -882,36 +891,24 @@ namespace nest throw UnknownSynapseType(synmodel_name.toString()); const index synmodel_id = static_cast(synmodel); - get_network().connect(source, target, weight, delay, synmodel_id); - - i->OStack.pop(5); - i->EStack.pop(); - } - - // Connect for gid gid weight delay syn_id - // See lib/sli/nest-init.sli for details - void NestModule::Connect_i_i_d_d_iFunction::execute(SLIInterpreter *i) const - { - i->assert_stack_load(5); - - index source = getValue(i->OStack.pick(4)); - index target = getValue(i->OStack.pick(3)); - double_t weight = getValue(i->OStack.pick(2)); - double_t delay = getValue(i->OStack.pick(1)); - index synmodel_id = getValue(i->OStack.pick(0)); - - get_network().connect(source, target, weight, delay, synmodel_id); + // check whether the target is on this process + if (get_network().is_local_gid(target)) + { + Node* const target_node = get_network().get_node(target); + const thread target_thread = target_node->get_thread(); + get_network().connect(source, target, target_node, target_thread, weight, delay, synmodel_id); + } i->OStack.pop(5); i->EStack.pop(); } - // Connect for gid gid dict + // Connect for gid gid params syn_model // See lib/sli/nest-init.sli for details void NestModule::Connect_i_i_D_lFunction::execute(SLIInterpreter *i) const { i->assert_stack_load(4); - + index source = getValue(i->OStack.pick(3)); index target = getValue(i->OStack.pick(2)); DictionaryDatum params = getValue(i->OStack.pick(1)); @@ -922,28 +919,37 @@ namespace nest throw UnknownSynapseType(synmodel_name.toString()); const index synmodel_id = static_cast(synmodel); - params->clear_access_flags(); - - if ( get_network().connect(source, target, params, synmodel_id) ) + // check whether the target is on this process + if (get_network().is_local_gid(target)) { - // dict access control only if we actually made a connection - std::string missed; - if ( !params->all_accessed(missed) ) - { - if ( get_network().dict_miss_is_error() ) - throw UnaccessedDictionaryEntry(missed); - else - get_network().message(SLIInterpreter::M_WARNING, "Connect", - ("Unread dictionary entries: " + missed).c_str()); - } + Node* const target_node = get_network().get_node(target); + const thread target_thread = target_node->get_thread(); + get_network().connect(source, target, target_node, target_thread, params, synmodel_id); } - + i->OStack.pop(4); i->EStack.pop(); } + // Connect for gidcollection gidcollection conn_spec syn_spec + // See lib/sli/nest-init.sli for details + void NestModule::Connect_g_g_D_DFunction::execute(SLIInterpreter *i) const + { + i->assert_stack_load(4); + + GIDCollectionDatum sources = getValue(i->OStack.pick(3)); + GIDCollectionDatum targets = getValue(i->OStack.pick(2)); + DictionaryDatum connectivity = getValue(i->OStack.pick(1)); + DictionaryDatum synapse_params = getValue(i->OStack.pick(0)); - /* BeginDocumentation + // dictionary access checking is handled by connect + get_network().connect(sources, targets, connectivity, synapse_params); + + i->OStack.pop(4); + i->EStack.pop(); + } + + /* BeginDocumentation Name: DataConnect_i_D_s - Connect many neurons from data. Synopsis: @@ -969,7 +975,9 @@ namespace nest DataConnect will iterate all vectors and create the connections according to the parameters given. SeeAlso: DataConnect_a, DataConnect Author: Marc-Oliver Gewaltig - */ + FirstVersion: August 2011 + SeeAlso: Connect, DivergentConnect + */ void NestModule::DataConnect_i_D_sFunction::execute(SLIInterpreter *i) const { i->assert_stack_load(3); @@ -977,6 +985,7 @@ namespace nest index source = getValue(i->OStack.pick(2)); DictionaryDatum params = getValue(i->OStack.pick(1)); const Name synmodel_name = getValue(i->OStack.pick(0)); + const Token synmodel = get_network().get_synapsedict().lookup(synmodel_name); if ( synmodel.empty() ) throw UnknownSynapseType(synmodel_name.toString()); @@ -1222,6 +1231,7 @@ namespace nest i->EStack.pop(); } + /* BeginDocumentation Name: MemoryInfo - Report current memory usage. Description: @@ -1462,6 +1472,29 @@ namespace nest i->EStack.pop(); } + /* BeginDocumentation + Name: SetNumRecProcesses - Set the number of MPI processes dedicated to recording spikes. + Synopsis: n_procs SetNumRecProcesses -> - + Description: + Sets the number of recording MPI processes to n_procs. Usually, + spike detectors are distributed over all processes and record + from local neurons only. If a number of processes is dedicated to + spike detection, each spike detector is hosted on one of these + processes and records globally from all simulating processes. + Availability: NEST 2.4 + Authors: Susanne Kunkel, Maximilian Schmidt + FirstVersion: April 2014 + SeeAlso: NumProcesses + */ + void NestModule::SetNumRecProcessesFunction_i::execute(SLIInterpreter *i) const + { + long n_rec_procs = getValue(i->OStack.pick(0)); + get_network().set_num_rec_processes(n_rec_procs); + i->OStack.pop(1); + i->EStack.pop(); + } + + /* BeginDocumentation Name: SyncProcesses - Synchronize all MPI processes. Synopsis: SyncProcesses -> - @@ -1508,6 +1541,32 @@ namespace nest i->OStack.push(time); i->EStack.pop(); } + /* BeginDocumentation + Name: TimeCommunicationv - returns average time taken for MPI_Allgatherv over n calls with m bytes + Synopsis: + n m TimeCommunication -> time + Availability: NEST 2.0 + Author: + FirstVersion: August 2012 + Description: + The function allows a user to test how much time a call the Allgatherv costs + Does not work for offgrid!!! + */ + void NestModule::TimeCommunicationv_i_iFunction::execute(SLIInterpreter *i) const + { + i->assert_stack_load(2); + long samples = getValue(i->OStack.pick(1)); + long num_bytes = getValue(i->OStack.pick(0)); + + + double_t time = 0.0; + + time = Communicator::time_communicatev(num_bytes,samples); + + i->OStack.pop(2); + i->OStack.push(time); + i->EStack.pop(); + } /* BeginDocumentation Name: ProcessorName - Returns a unique specifier for the actual node. @@ -1677,6 +1736,53 @@ namespace nest i->EStack.pop(); } + void NestModule::Cvgidcollection_i_iFunction::execute(SLIInterpreter *i) const + { + i->assert_stack_load(2); + + const long_t first = getValue(i->OStack.pick(1)); + const long_t last = getValue(i->OStack.pick(0)); + GIDCollectionDatum gidcoll = GIDCollection(first, last); + + i->OStack.pop(2); + i->OStack.push(gidcoll); + i->EStack.pop(); + } + + void NestModule::Cvgidcollection_iaFunction::execute(SLIInterpreter *i) const + { + i->assert_stack_load(1); + + TokenArray gids = getValue(i->OStack.pick(0)); + GIDCollectionDatum gidcoll = GIDCollection(gids); + + i->OStack.pop(); + i->OStack.push(gidcoll); + i->EStack.pop(); + } + + void NestModule::Cvgidcollection_ivFunction::execute(SLIInterpreter *i) const + { + i->assert_stack_load(1); + + IntVectorDatum gids = getValue(i->OStack.pick(0)); + GIDCollectionDatum gidcoll = GIDCollection(gids); + + i->OStack.pop(); + i->OStack.push(gidcoll); + i->EStack.pop(); + } + + void NestModule::Size_gFunction::execute(SLIInterpreter *i) const + { + i->assert_stack_load(1); + GIDCollectionDatum gidcoll = getValue(i->OStack.pick(0)); + + i->OStack.pop(); + i->OStack.push(gidcoll.size()); + i->EStack.pop(); + } + #ifdef HAVE_MUSIC /* BeginDocumentation Name: SetAcceptableLatency - set the acceptable latency of a MUSIC input port @@ -1705,6 +1811,19 @@ namespace nest i->OStack.pop(2); i->EStack.pop(); } + + void NestModule::SetMaxBufferedFunction::execute(SLIInterpreter *i) const + { + i->assert_stack_load(2); + + std::string port_name = getValue(i->OStack.pick(1)); + int maxBuffered = getValue(i->OStack.pick(0)); + + get_network().set_music_in_port_max_buffered(port_name, maxBuffered); + + i->OStack.pop(2); + i->EStack.pop(); + } #endif void NestModule::init(SLIInterpreter *i) @@ -1712,6 +1831,9 @@ namespace nest ConnectionType.settypename("connectiontype"); ConnectionType.setdefaultaction(SLIInterpreter::datatypefunction); + GIDCollectionType.settypename("gidcollectiontype"); + GIDCollectionType.setdefaultaction(SLIInterpreter::datatypefunction); + // ensure we have a network: it is created outside and registered via register_network() assert(net_ != 0); @@ -1749,10 +1871,11 @@ namespace nest i->createcommand("Create_l_i", &create_l_ifunction); i->createcommand("Connect_i_i_l", &connect_i_i_lfunction); - i->createcommand("Connect_i_i_i", &connect_i_i_ifunction); i->createcommand("Connect_i_i_d_d_l", &connect_i_i_d_d_lfunction); - i->createcommand("Connect_i_i_d_d_i", &connect_i_i_d_d_ifunction); i->createcommand("Connect_i_i_D_l", &connect_i_i_D_lfunction); + + i->createcommand("Connect_g_g_D_D", &connect_g_g_D_Dfunction); + i->createcommand("DataConnect_i_D_s", &dataconnect_i_D_sfunction); i->createcommand("DataConnect_a", &dataconnect_afunction); @@ -1777,8 +1900,10 @@ namespace nest i->createcommand("Rank", &rankfunction); i->createcommand("NumProcesses", &numprocessesfunction); i->createcommand("SetFakeNumProcesses", &setfakenumprocesses_ifunction); + i->createcommand("SetNumRecProcesses", &setnumrecprocesses_ifunction); i->createcommand("SyncProcesses", &syncprocessesfunction); i->createcommand("TimeCommunication_i_i_b", &timecommunication_i_i_bfunction); + i->createcommand("TimeCommunicationv_i_i", &timecommunicationv_i_ifunction); i->createcommand("ProcessorName", &processornamefunction); #ifdef HAVE_MPI i->createcommand("MPI_Abort", &mpiabort_ifunction); @@ -1789,14 +1914,30 @@ namespace nest i->createcommand("cvdict_C", &cvdict_Cfunction); + i->createcommand("cvgidcollection_i_i", &cvgidcollection_i_ifunction); + i->createcommand("cvgidcollection_ia", &cvgidcollection_iafunction); + i->createcommand("cvgidcollection_iv", &cvgidcollection_ivfunction); + i->createcommand("size_g", &size_gfunction); + #ifdef HAVE_MUSIC i->createcommand("SetAcceptableLatency", &setacceptablelatency_l_dfunction); + i->createcommand("SetMaxBuffered", &setmaxbuffered_l_ifunction); #endif - + + // Add connection rules + net_->register_conn_builder("one_to_one"); + net_->register_conn_builder("all_to_all"); + net_->register_conn_builder("fixed_indegree"); + net_->register_conn_builder("fixed_outdegree"); + net_->register_conn_builder("pairwise_bernoulli"); + + #ifdef HAVE_GSL + net_->register_conn_builder("fixed_total_number"); + #endif + Token statusd = i->baselookup(Name("statusdict")); DictionaryDatum dd=getValue(statusd); dd->insert(Name("kernelname"), new StringDatum("NEST")); - dd->insert(Name("kernelrevision"), new StringDatum("$Revision: 10474 $")); dd->insert(Name("is_mpi"), new BoolDatum(Communicator::get_initialized())); } diff --git a/nestkernel/nestmodule.h b/nestkernel/nestmodule.h index 5f0ec2b1ea..2075c375a0 100644 --- a/nestkernel/nestmodule.h +++ b/nestkernel/nestmodule.h @@ -22,22 +22,12 @@ #ifndef NESTMODULE_H #define NESTMODULE_H -/* - This file is part of NEST - nestmodule.h -- Header to the nestmodule - (see cpp file for details) - - Author: Marc-Oliver Gewaltig (marc-oliver.gewaltig@honda-ri.de) - - $Date: 2013-05-23 15:41:44 +0200 (Thu, 23 May 2013) $ - Last change: $Author: zaytsev $ - $Revision: 10474 $ -*/ #include "slimodule.h" +#include "slitype.h" #include "slifunction.h" -#include "slitype.h" #include "dict.h" + #include "network.h" #include "scheduler.h" #include "event.h" @@ -56,8 +46,9 @@ namespace nest class NestModule: public SLIModule { public: - + static SLIType ConnectionType; + static SLIType GIDCollectionType; NestModule(); ~NestModule(); @@ -131,6 +122,8 @@ namespace nest * - @c os : output stream * - @c t : any token * - @c C : connectiontype + * - @c cg : connectiongeneratortype + * - @c g : gid collection * * @subsection compoundtypes Codes for compund data types * - @c A : array @@ -260,9 +253,8 @@ namespace nest void execute(SLIInterpreter *) const; } copymodel_l_l_Dfunction; - class GetConnections_DFunction: public SLIFunction - { + { public: void execute(SLIInterpreter *) const; } getconnections_Dfunction; @@ -309,29 +301,23 @@ namespace nest void execute(SLIInterpreter *) const; } connect_i_i_lfunction; - class Connect_i_i_iFunction: public SLIFunction - { - public: - void execute(SLIInterpreter *) const; - } connect_i_i_ifunction; - class Connect_i_i_d_d_lFunction: public SLIFunction { public: void execute(SLIInterpreter *) const; } connect_i_i_d_d_lfunction; - class Connect_i_i_d_d_iFunction: public SLIFunction + class Connect_i_i_D_lFunction: public SLIFunction { public: void execute(SLIInterpreter *) const; - } connect_i_i_d_d_ifunction; + } connect_i_i_D_lfunction; - class Connect_i_i_D_lFunction: public SLIFunction + class Connect_g_g_D_DFunction: public SLIFunction { - public: + public: void execute(SLIInterpreter *) const; - } connect_i_i_D_lfunction; + } connect_g_g_D_Dfunction; class DivergentConnect_i_ia_a_a_lFunction: public SLIFunction { @@ -407,6 +393,11 @@ namespace nest void execute(SLIInterpreter *) const; } setfakenumprocesses_ifunction; + class SetNumRecProcessesFunction_i : public SLIFunction + { + void execute(SLIInterpreter *) const; + } setnumrecprocesses_ifunction; + class SyncProcessesFunction : public SLIFunction { void execute(SLIInterpreter *) const; @@ -416,6 +407,11 @@ namespace nest { void execute(SLIInterpreter *) const; } timecommunication_i_i_bfunction; + + class TimeCommunicationv_i_iFunction : public SLIFunction + { + void execute(SLIInterpreter *) const; + } timecommunicationv_i_ifunction; class ProcessorNameFunction : public SLIFunction { @@ -444,11 +440,36 @@ namespace nest void execute(SLIInterpreter *) const; } cvdict_Cfunction; + class Cvgidcollection_i_iFunction : public SLIFunction + { + void execute(SLIInterpreter *) const; + } cvgidcollection_i_ifunction; + + class Cvgidcollection_iaFunction : public SLIFunction + { + void execute(SLIInterpreter *) const; + } cvgidcollection_iafunction; + + class Cvgidcollection_ivFunction : public SLIFunction + { + void execute(SLIInterpreter *) const; + } cvgidcollection_ivfunction; + + class Size_gFunction: public SLIFunction + { + void execute(SLIInterpreter *) const; + } size_gfunction; + #ifdef HAVE_MUSIC class SetAcceptableLatencyFunction : public SLIFunction { void execute(SLIInterpreter *) const; } setacceptablelatency_l_dfunction; + + class SetMaxBufferedFunction : public SLIFunction + { + void execute(SLIInterpreter *) const; + } setmaxbuffered_l_ifunction; #endif //@} @@ -469,21 +490,21 @@ namespace nest static Network *net_; }; -inline -Network &NestModule::get_network() -{ - assert(net_ != 0); - return *net_; -} - -inline -index NestModule::get_num_threads() -{ - if ( net_ == 0 ) - return 1; // module not initialized, thus certainly single thread - else - return net_->get_num_threads(); -} + inline + Network &NestModule::get_network() + { + assert(net_ != 0); + return *net_; + } + + inline + index NestModule::get_num_threads() + { + if ( net_ == 0 ) + return 1; // module not initialized, thus certainly single thread + else + return net_->get_num_threads(); + } } // namespace diff --git a/nestkernel/network.cpp b/nestkernel/network.cpp index ff1b16f254..ffffde7c80 100644 --- a/nestkernel/network.cpp +++ b/nestkernel/network.cpp @@ -22,6 +22,7 @@ #include "instance.h" #include "network.h" +#include "network_impl.h" #include "genericmodel.h" #include "scheduler.h" #include "subnet.h" @@ -83,13 +84,17 @@ Network::Network(SLIInterpreter &i) synapsedict_ = new Dictionary(); interpreter_.def("synapsedict", new DictionaryDatum(synapsedict_)); connection_manager_.init(synapsedict_); + + connruledict_ = new Dictionary(); + interpreter_.def("connruledict", new DictionaryDatum(connruledict_)); + init_(); } Network::~Network() { destruct_nodes_(); - clear_models_(); + clear_models_(true); // mark call from destructor // Now we can delete the clean model prototypes vector< std::pair >::iterator i; @@ -113,7 +118,7 @@ void Network::init_() root_container->reserve(get_num_threads()); root_container->set_model_id(-1); - assert(pristine_models_.size() > 0); + assert( !pristine_models_.empty() ); Model* rootmodel= pristine_models_[0].first; assert(rootmodel != 0); @@ -184,7 +189,7 @@ void Network::init_() void Network::destruct_nodes_() { // We call the destructor for each node excplicitly. This destroys - // the objects without releasing their memory. since the Memory is + // the objects without releasing their memory. Since the Memory is // owned by the Model objects, we must not call delete on the Node // objects! for(size_t n = 0; n < nodes_.size(); ++n) @@ -203,8 +208,13 @@ void Network::destruct_nodes_() dummy_spike_sources_.clear(); } -void Network::clear_models_() +void Network::clear_models_(bool called_from_destructor) { + // no message on destructor call, may come after MPI_Finalize() + if ( not called_from_destructor ) + message(SLIInterpreter::M_INFO, "Network::clear_models", + "Models will be cleared and parameters reset."); + // We delete all models, which will also delete all nodes. The // built-in models will be recovered from the pristine_models_ in // init_() @@ -238,6 +248,7 @@ void Network::reset() void Network::reset_kernel() { scheduler_.set_num_threads(1); + scheduler_.set_num_rec_processes(0); data_path_ = ""; data_prefix_ = ""; overwrite_files_ = false; @@ -248,11 +259,13 @@ void Network::reset_kernel() void Network::reset_network() { + force_preparation(); if ( !scheduler_.get_simulated() ) return; // nothing to do /* Reinitialize state on all nodes, force init_buffers() on next - Simulate Finding all nodes is non-trivial: + call to simulate(). + Finding all nodes is non-trivial: - Nodes with proxies are found in nodes_. This is also true for any nodes that are part of Subnets. - Nodes without proxies are not registered in nodes_. Instead, a @@ -312,6 +325,8 @@ index Network::add_node(index mod, long_t n) //no_p assert(current_ != 0); assert(root_ != 0); + force_preparation(); + if(mod >= models_.size()) throw UnknownModelID(mod); @@ -348,17 +363,52 @@ index Network::add_node(index mod, long_t n) //no_p } node_model_ids_.add_range(mod,min_gid,max_gid-1); - if (model->has_proxies()) + if (model->potential_global_receiver() and scheduler_.get_num_rec_processes() > 0) { // In this branch we create nodes for all GIDs which are on a local thread - // and proxies for all GIDs which are on remote processes. - const int n_per_process = n / scheduler_.get_num_processes(); + const int n_per_process = n / scheduler_.get_num_rec_processes(); + const int n_per_thread = n_per_process / n_threads + 1; + + nodes_.resize(max_gid); + for (thread t = 0; t < n_threads; ++t) + model->reserve(t, n_per_thread); // Model::reserve() reserves memory for n ADDITIONAL nodes on thread t + + for ( size_t gid = min_gid; gid < max_gid; ++gid ) + { + const thread vp = (current_->get_children_on_same_vp()) + ? current_->get_children_vp() : suggest_rec_vp(scheduler_.get_n_gsd()); + const thread t = vp_to_thread(vp); + + if( is_local_vp(vp) ) + { + Node *newnode = model->allocate(t); + newnode->set_gid_(gid); + newnode->set_model_id(mod); + newnode->set_thread(t); + newnode->set_vp(vp); + newnode->set_has_proxies(true); + newnode->set_local_receiver(false); + nodes_[gid] = newnode; // put into local nodes list + current_->add_node(newnode); // and into current subnet, thread 0. + } + else + current_->add_remote_node(gid, mod); + + scheduler_.increment_n_gsd(); + } + } + + else if (model->has_proxies()) + { + // In this branch we create nodes for all GIDs which are on a local thread + const int n_per_process = n / scheduler_.get_num_sim_processes(); const int n_per_thread = n_per_process / n_threads + 1; nodes_.resize(max_gid); for(thread t = 0; t < n_threads; ++t) model->reserve(t, n_per_thread); // Model::reserve() reserves memory for n ADDITIONAL nodes on thread t + for(size_t gid = min_gid; gid < max_gid; ++gid) { thread vp = (current_->get_children_on_same_vp()) ? current_->get_children_vp() : suggest_vp(gid); @@ -366,8 +416,7 @@ index Network::add_node(index mod, long_t n) //no_p if(is_local_vp(vp)) { - Node *newnode = 0; - newnode = model->allocate(t); + Node *newnode = model->allocate(t); newnode->set_gid_(gid); newnode->set_model_id(mod); newnode->set_thread(t); @@ -380,7 +429,7 @@ index Network::add_node(index mod, long_t n) //no_p current_->add_remote_node(gid,mod); } } - else if (!model->one_node_per_process()) + else if ( !model->one_node_per_process() ) { // We allocate space for n containers which will hold the threads // sorted. We use SiblingContainers to store the instances for @@ -411,7 +460,7 @@ index Network::add_node(index mod, long_t n) //no_p // since we create the n nodes on each thread, we reserve the full load. for(thread t = 0; t < n_threads; ++t) { - model->reserve(t,n); + model->reserve(t, n); siblingcontainer_model->reserve(t, container_per_thread); static_cast(subnet_container->get_thread_sibling_(t))->reserve(n); } @@ -420,12 +469,10 @@ index Network::add_node(index mod, long_t n) //no_p // and filled with one instance per thread, in total n * n_thread nodes in // n wrappers. nodes_.resize(max_gid); - for(index gid = min_gid; gid < max_gid; ++gid) + for (index gid = min_gid; gid < max_gid; ++gid) { thread thread_id = vp_to_thread(suggest_vp(gid)); - //std::cout << "gid " << gid << ", size of nodes " << nodes_.size() << std::endl; - // Create wrapper and register with nodes_ array. SiblingContainer *container= static_cast(siblingcontainer_model->allocate(thread_id)); container->set_model_id(-1); // mark as pseudo-container wrapping replicas, see reset_network() @@ -433,7 +480,7 @@ index Network::add_node(index mod, long_t n) //no_p nodes_[gid] = container; // Generate one instance of desired model per thread - for(thread t = 0; t < n_threads; ++t) + for (thread t = 0; t < n_threads; ++t) { Node *newnode = model->allocate(t); newnode->set_gid_(gid); // all instances get the same global id. @@ -469,8 +516,6 @@ index Network::add_node(index mod, long_t n) //no_p for(index gid = min_gid; gid < max_gid; ++gid) { - //std::cout << "gid " << gid << ", size of nodes " << nodes_.size() << std::endl; - Node *newnode = model->allocate(0); newnode->set_gid_(gid); newnode->set_model_id(mod); @@ -497,39 +542,40 @@ index Network::add_node(index mod, long_t n) //no_p return max_gid - 1; } - void Network::restore_nodes(ArrayDatum &node_list) - { - Subnet *root= get_cwn(); - const index gid_offset= size()-1; - Token *first=node_list.begin(); - const Token *end=node_list.end(); - if(first == end) - return; - // We need to know the first and hopefully smallest GID to identify - // if a parent is in or outside the range of restored nodes. - // So we retrieve it here, from the first element of the node_list, assuming that - // the node GIDs are in ascending order. - DictionaryDatum node_props=getValue(*first); - const index min_gid=(*node_props)[names::global_id]; - - for (Token *node_t=first; node_t != end; ++node_t) - { - DictionaryDatum node_props=getValue(*node_t); - std::string model_name= (*node_props)[names::model]; - index model_id=get_model_id(model_name.c_str()); - index parent_gid=(*node_props)[names::parent]; - index local_parent_gid= parent_gid; - if(parent_gid >= min_gid) // if the parent is one of the restored nodes - local_parent_gid += gid_offset; // we must add the gid_offset - go_to(local_parent_gid); - index node_gid=add_node(model_id); - Node *node_ptr=get_node(node_gid); - // we call directly set_status on the node - // to bypass checking of unused dictionary items. - node_ptr->set_status_base(node_props); - } - current_=root; - } + void Network::restore_nodes(ArrayDatum &node_list) + { + force_preparation(); + Subnet *root= get_cwn(); + const index gid_offset= size()-1; + Token *first=node_list.begin(); + const Token *end=node_list.end(); + if(first == end) + return; + // We need to know the first and hopefully smallest GID to identify + // if a parent is in or outside the range of restored nodes. + // So we retrieve it here, from the first element of the node_list, assuming that + // the node GIDs are in ascending order. + DictionaryDatum node_props=getValue(*first); + const index min_gid=(*node_props)[names::global_id]; + + for (Token *node_t=first; node_t != end; ++node_t) + { + DictionaryDatum node_props=getValue(*node_t); + std::string model_name= (*node_props)[names::model]; + index model_id=get_model_id(model_name.c_str()); + index parent_gid=(*node_props)[names::parent]; + index local_parent_gid= parent_gid; + if(parent_gid >= min_gid) // if the parent is one of the restored nodes + local_parent_gid += gid_offset; // we must add the gid_offset + go_to(local_parent_gid); + index node_gid=add_node(model_id); + Node *node_ptr=get_node(node_gid); + // we call directly set_status on the node + // to bypass checking of unused dictionary items. + node_ptr->set_status_base(node_props); + } + current_=root; + } void Network::init_state(index GID) { @@ -689,7 +735,7 @@ void Network::set_status(index gid, const DictionaryDatum& d) // of threads changes. HEP, 2008-10-20 Node &target= *(nodes_[gid]); - for(size_t t=0; t < target.num_thread_siblings_(); ++t) + for (size_t t=0; t < target.num_thread_siblings_(); ++t) { // Root container for per-thread subnets. We must prevent clearing of access // flags before each compound's properties are set by passing false as last arg @@ -782,92 +828,160 @@ DictionaryDatum Network::get_status(index idx) return d; } -// gid gid -void Network::connect(index source_id, index target_id, index syn) +// gid gid node thread weight delay syn +void Network::connect(index sgid, index tgid, Node* target, thread target_thread, double_t w, double_t d, index syn) { - if (!is_local_gid(target_id)) - return; - - Node* target_ptr = get_node(target_id); + // TODO: is this necessary? + force_preparation(); - Node* source_ptr = 0; - //target_thread defaults to 0 for devices - thread target_thread = target_ptr->get_thread(); - source_ptr = get_node(source_id, target_thread); + Node * const source = get_node(sgid, target_thread); //normal nodes and devices with proxies - if (target_ptr->has_proxies()) + if (target->has_proxies()) { - connect(*source_ptr, *target_ptr, source_id, target_thread, syn); + connect(*source, *target, sgid, target_thread, w, d, syn); } - else if (target_ptr->local_receiver()) //normal devices + else if (target->local_receiver()) //normal devices { - if(source_ptr->is_proxy()) + if(source->is_proxy()) return; - if ((source_ptr->get_thread() != target_thread) && (source_ptr->has_proxies())) + if ((source->get_thread() != target_thread) && (source->has_proxies())) { - target_thread = source_ptr->get_thread(); - target_ptr = get_node(target_id, target_thread); + target_thread = source->get_thread(); + target = get_node(tgid, target_thread); } - connect(*source_ptr, *target_ptr, source_id, target_thread, syn); + connect(*source, *target, sgid, target_thread, w, d, syn); } else //globally receiving devices iterate over all target threads { - //we do not allow to connect a device to a global receiver at the moment - if (!source_ptr->has_proxies()) - throw IllegalConnection("Devices cannot be connected to global receivers."); + if (!source->has_proxies()) //we do not allow to connect a device to a global receiver at the moment + return; + const thread n_threads = get_num_threads(); + for (thread t = 0; t < n_threads; t++) + { + target = get_node(tgid, t); + connect(*source, *target, sgid, t, w, d, syn); + } + } +} + +// gid gid node thread syn +void Network::connect(index sgid, index tgid, Node* target, thread target_thread, index syn) +{ + // TODO: is this necessary? + force_preparation(); + + Node * const source = get_node(sgid, target_thread); + + //normal nodes and devices with proxies + if (target->has_proxies()) + { + connect(*source, *target, sgid, target_thread, syn); + } + else if (target->local_receiver()) //normal devices + { + if(source->is_proxy()) + return; + + if ((source->get_thread() != target_thread) && (source->has_proxies())) + { + target_thread = source->get_thread(); + target = get_node(tgid, target_thread); + } + connect(*source, *target, sgid, target_thread, syn); + } + else //globally receiving devices iterate over all target threads + { + if (!source->has_proxies()) //we do not allow to connect a device to a global receiver at the moment + return; const thread n_threads = get_num_threads(); for (thread t = 0; t < n_threads; t++) { - target_ptr = get_node(target_id, t); - connect(*source_ptr, *target_ptr, source_id, t, syn); + target = get_node(tgid, t); + connect(*source, *target, sgid, t, syn); } } } -// gid gid weight delay -void Network::connect(index source_id, index target_id, double_t w, double_t d, index syn) +// gid gid node thread weight delay dict syn +void Network::connect(index sgid, index tgid, Node* target, thread target_thread, double_t w, double_t d, + DictionaryDatum& params, index syn) { - if (!is_local_gid(target_id)) - return; + // TODO: is this necessary? + force_preparation(); - Node* target_ptr = get_node(target_id); + Node * const source = get_node(sgid, target_thread); - Node* source_ptr = 0; - //target_thread defaults to 0 for devices - thread target_thread = target_ptr->get_thread(); - source_ptr = get_node(source_id, target_thread); + //normal nodes and devices with proxies + if (target->has_proxies()) + { + connect(*source, *target, sgid, target_thread, w, d, params, syn); + } + else if (target->local_receiver()) //normal devices + { + if(source->is_proxy()) + return; + + if ((source->get_thread() != target_thread) && (source->has_proxies())) + { + target_thread = source->get_thread(); + target = get_node(tgid, target_thread); + } + + connect(*source, *target, sgid, target_thread, w, d, params, syn); + } + else //globally receiving devices iterate over all target threads + { + if (!source->has_proxies()) //we do not allow to connect a device to a global receiver at the moment + return; + const thread n_threads = get_num_threads(); + for (thread t = 0; t < n_threads; t++) + { + target = get_node(tgid, t); + connect(*source, *target, sgid, t, w, d, params, syn); + } + } +} + +// gid gid node thread dict syn +void Network::connect(index sgid, index tgid, Node* target, thread target_thread, + DictionaryDatum& params, index syn) +{ + // TODO: is this necessary? + force_preparation(); + + Node * const source = get_node(sgid, target_thread); //normal nodes and devices with proxies - if (target_ptr->has_proxies()) + if (target->has_proxies()) { - connect(*source_ptr, *target_ptr, source_id, target_thread, w, d, syn); + connect(*source, *target, sgid, target_thread, params, syn); } - else if (target_ptr->local_receiver()) //normal devices + else if (target->local_receiver()) //normal devices { - if(source_ptr->is_proxy()) + if(source->is_proxy()) return; - if ((source_ptr->get_thread() != target_thread) && (source_ptr->has_proxies())) + if ((source->get_thread() != target_thread) && (source->has_proxies())) { - target_thread = source_ptr->get_thread(); - target_ptr = get_node(target_id, target_thread); + target_thread = source->get_thread(); + target = get_node(tgid, target_thread); } - connect(*source_ptr, *target_ptr, source_id, target_thread, w, d, syn); + connect(*source, *target, sgid, target_thread, params, syn); } else //globally receiving devices iterate over all target threads { - if (!source_ptr->has_proxies()) //we do not allow to connect a device to a global receiver at the moment + if (!source->has_proxies()) //we do not allow to connect a device to a global receiver at the moment return; const thread n_threads = get_num_threads(); for (thread t = 0; t < n_threads; t++) { - target_ptr = get_node(target_id, t); - connect(*source_ptr, *target_ptr, source_id, t, w, d, syn); + target = get_node(tgid, t); + connect(*source, *target, sgid, t, params, syn); } } } @@ -875,15 +989,18 @@ void Network::connect(index source_id, index target_id, double_t w, double_t d, // gid gid dict bool Network::connect(index source_id, index target_id, DictionaryDatum& params, index syn) { + if (!is_local_gid(target_id)) return false; + force_preparation(); + Node* target_ptr = get_node(target_id); - Node* source_ptr = 0; //target_thread defaults to 0 for devices thread target_thread = target_ptr->get_thread(); - source_ptr = get_node(source_id, target_thread); + + Node* source_ptr = get_node(source_id, target_thread); //normal nodes and devices with proxies if (target_ptr->has_proxies()) @@ -924,6 +1041,9 @@ bool Network::connect(index source_id, index target_id, DictionaryDatum& params, void Network::divergent_connect(index source_id, const TokenArray target_ids, const TokenArray weights, const TokenArray delays, index syn) { + force_preparation(); + + bool complete_wd_lists = (target_ids.size() == weights.size() && weights.size() != 0 && weights.size() == delays.size()); @@ -985,36 +1105,53 @@ void Network::divergent_connect(index source_id, const TokenArray target_ids, try { if (complete_wd_lists) + { connect(*source, *targets[i], source_id, target_thread, weights.get(i), delays.get(i), syn); + } else if (short_wd_lists) + { connect(*source, *targets[i], source_id, target_thread, weights.get(0), delays.get(0), syn); + } else + { connect(*source, *targets[i], source_id, target_thread, syn); + } } catch (IllegalConnection& e) { - std::string msg - = String::compose("Target with ID %1 does not support the connection. " - "The connection will be ignored.", targets[i]->get_gid()); + std::string msg = String::compose("Target with ID %1 does not support the connection. " + "The connection will be ignored.", + targets[i]->get_gid()); if ( ! e.message().empty() ) - msg += "\nDetails: " + e.message(); + msg += "\nDetails: " + e.message(); message(SLIInterpreter::M_WARNING, "DivergentConnect", msg.c_str()); continue; } catch (UnknownReceptorType& e) { - std::string msg - = String::compose("In Connection from global source ID %1 to target ID %2: " - "Target does not support requested receptor type. " - "The connection will be ignored", - source->get_gid(), targets[i]->get_gid()); + std::string msg = String::compose("In Connection from global source ID %1 to target ID %2: " + "Target does not support requested receptor type. " + "The connection will be ignored", + source->get_gid(), targets[i]->get_gid()); if ( ! e.message().empty() ) - msg += "\nDetails: " + e.message(); + msg += "\nDetails: " + e.message(); + message(SLIInterpreter::M_WARNING, "DivergentConnect", msg.c_str()); + continue; + } + catch (TypeMismatch& e) + { + std::string msg = String::compose("In Connection from global source ID %1 to target ID %2: " + "Expect source and weights of type double. " + "The connection will be ignored", + source->get_gid(), targets[i]->get_gid()); + if (!e.message().empty()) + msg += "\nDetails: " + e.message(); message(SLIInterpreter::M_WARNING, "DivergentConnect", msg.c_str()); continue; } } } + // ----------------------------------------------------------------------------- @@ -1023,6 +1160,8 @@ void Network::divergent_connect(index source_id, DictionaryDatum pars, index syn // We extract the parameters from the dictionary explicitly since getValue() for DoubleVectorDatum // copies the data into an array, from which the data must then be copied once more. + force_preparation(); + DictionaryDatum par_i(new Dictionary()); Dictionary::iterator di_s, di_t; // To save time, we first create the parameter dictionary for connect(), then we copy @@ -1102,26 +1241,24 @@ void Network::divergent_connect(index source_id, DictionaryDatum pars, index syn return; } - // We retrieve pointers for all targets, this implicitly checks if they - // exist and throws UnknownNode if not. - std::vector targets(target_ids.size()); size_t n_targets=target_ids.size(); - for (index i = 0; i < n_targets; ++i) - targets[i] = get_node(target_ids[i]); - for(index i = 0; i < n_targets; ++i) { - if (targets[i]->is_proxy()) - continue; - - thread target_thread = targets[i]->get_thread(); - - if (source->get_thread() != target_thread) - source = get_node(source_id, target_thread); - - if (!targets[i]->has_proxies() && source->is_proxy()) + Node *ptarget=0; + try + { + ptarget=get_node(target_ids[i]); + } + catch(UnknownNode &e) + { + std::string msg = String::compose("Target with ID %1 does not exist. " + "The connection will be ignored.", target_ids[i]); + if ( ! e.message().empty() ) + msg += "\nDetails: " + e.message(); + message(SLIInterpreter::M_WARNING, "DivergentConnect", msg.c_str()); continue; - + } + // here we fill a parameter dictionary with the values of the current loop index. for(di_s=(*pars).begin(), di_t=par_i->begin(); di_s !=(*pars).end();++di_s,++di_t) { @@ -1133,28 +1270,34 @@ void Network::divergent_connect(index source_id, DictionaryDatum pars, index syn try { - connect(source->get_gid(), targets[i]->get_gid(), par_i, syn); - + connect(source_id, target_ids[i], par_i, syn); } + catch (UnexpectedEvent& e) + { + std::string msg = String::compose("Target with ID %1 does not support the connection. " + "The connection will be ignored.", target_ids[i]); + if ( ! e.message().empty() ) + msg += "\nDetails: " + e.message(); + message(SLIInterpreter::M_WARNING, "DivergentConnect", msg.c_str()); + continue; + } catch (IllegalConnection& e) { - std::string msg - = String::compose("Target with ID %1 does not support the connection. " - "The connection will be ignored.", targets[i]->get_gid()); + std::string msg = String::compose("Target with ID %1 does not support the connection. " + "The connection will be ignored.", target_ids[i]); if ( ! e.message().empty() ) - msg += "\nDetails: " + e.message(); + msg += "\nDetails: " + e.message(); message(SLIInterpreter::M_WARNING, "DivergentConnect", msg.c_str()); continue; } catch (UnknownReceptorType& e) { - std::string msg - = String::compose("In Connection from global source ID %1 to target ID %2: " - "Target does not support requested receptor type. " - "The connection will be ignored", - source->get_gid(), targets[i]->get_gid()); + std::string msg = String::compose("In Connection from global source ID %1 to target ID %2: " + "Target does not support requested receptor type. " + "The connection will be ignored", + source_id, target_ids[i]); if ( ! e.message().empty() ) - msg += "\nDetails: " + e.message(); + msg += "\nDetails: " + e.message(); message(SLIInterpreter::M_WARNING, "DivergentConnect", msg.c_str()); continue; } @@ -1164,6 +1307,9 @@ void Network::divergent_connect(index source_id, DictionaryDatum pars, index syn void Network::random_divergent_connect(index source_id, const TokenArray target_ids, index n, const TokenArray weights, const TokenArray delays, bool allow_multapses, bool allow_autapses, index syn) { + + force_preparation(); + Node *source = get_node(source_id); // check if we have consistent lists for weights and delays @@ -1225,6 +1371,8 @@ void Network::convergent_connect(const TokenArray source_ids, index target_id, c bool short_wd_lists = (source_ids.size() != weights.size() && weights.size() == 1 && delays.size() == 1); bool no_wd_lists = (weights.size() == 0 && delays.size() == 0); + force_preparation(); + // check if we have consistent lists for weights and delays if (! (complete_wd_lists || short_wd_lists || no_wd_lists)) { @@ -1279,31 +1427,47 @@ void Network::convergent_connect(const TokenArray source_ids, index target_id, c try { if (complete_wd_lists) + { connect(*source, *target, source_id, target_thread, weights.get(i), delays.get(i), syn); + } else if (short_wd_lists) + { connect(*source, *target, source_id, target_thread, weights.get(0), delays.get(0), syn); + } else + { connect(*source, *target, source_id, target_thread, syn); + } } catch (IllegalConnection& e) { - std::string msg - = String::compose("Target with ID %1 does not support the connection. " - "The connection will be ignored.", target->get_gid()); + std::string msg = String::compose("Target with ID %1 does not support the connection. " + "The connection will be ignored.", + target->get_gid()); if ( ! e.message().empty() ) - msg += "\nDetails: " + e.message(); + msg += "\nDetails: " + e.message(); message(SLIInterpreter::M_WARNING, "ConvergentConnect", msg.c_str()); continue; } catch (UnknownReceptorType& e) { - std::string msg - = String::compose("In Connection from global source ID %1 to target ID %2: " - "Target does not support requested receptor type. " - "The connection will be ignored", - source->get_gid(), target->get_gid()); + std::string msg = String::compose("In Connection from global source ID %1 to target ID %2: " + "Target does not support requested receptor type. " + "The connection will be ignored", + source->get_gid(), target->get_gid()); if ( ! e.message().empty() ) - msg += "\nDetails: " + e.message(); + msg += "\nDetails: " + e.message(); + message(SLIInterpreter::M_WARNING, "ConvergentConnect", msg.c_str()); + continue; + } + catch (TypeMismatch& e) + { + std::string msg = String::compose("In Connection from global source ID %1 to target ID %2: " + "Expect source and weights of type double. " + "The connection will be ignored", + source->get_gid(), target->get_gid()); + if (!e.message().empty()) + msg += "\nDetails: " + e.message(); message(SLIInterpreter::M_WARNING, "ConvergentConnect", msg.c_str()); continue; } @@ -1320,21 +1484,12 @@ void Network::convergent_connect(const std::vector & source_ids, const st { bool complete_wd_lists = (sources.size() == weights.size() && weights.size() != 0 && weights.size() == delays.size()); bool short_wd_lists = (sources.size() != weights.size() && weights.size() == 1 && delays.size() == 1); - bool no_wd_lists = (weights.size() == 0 && delays.size() == 0); - - // Check if we have consistent lists for weights and delays - // TODO: This check should already be performed outside the parallel - // section of the threadedrandom_convergent_connect(). Throwing an - // exception inside a parallel section is not allowed. - if (! (complete_wd_lists || short_wd_lists || no_wd_lists)) - { - message(SLIInterpreter::M_ERROR, "ConvergentConnect", - "weights and delays must be either doubles or lists of equal size. " - "If given as lists, their size must be 1 or the same size as sources."); - throw DimensionMismatch(); - } + force_preparation(); + // Check if we have consistent lists for weights and delays + // already checked in previous RCC call + Node* target = get_node(target_id); for(index i = 0; i < sources.size(); ++i) { @@ -1356,19 +1511,25 @@ void Network::convergent_connect(const std::vector & source_ids, const st try { if (complete_wd_lists) + { connect(*source, *target, source_ids[i], target_thread, weights.get(i), delays.get(i), syn); + } else if (short_wd_lists) + { connect(*source, *target, source_ids[i], target_thread, weights.get(0), delays.get(0), syn); - else + } + else + { connect(*source, *target, source_ids[i], target_thread, syn); + } } catch (IllegalConnection& e) { - std::string msg - = String::compose("Target with ID %1 does not support the connection. " - "The connection will be ignored.", target->get_gid()); + std::string msg = String::compose("Target with ID %1 does not support the connection. " + "The connection will be ignored.", + target->get_gid()); if ( ! e.message().empty() ) - msg += "\nDetails: " + e.message(); + msg += "\nDetails: " + e.message(); message(SLIInterpreter::M_WARNING, "ConvergentConnect", msg.c_str()); continue; } @@ -1379,7 +1540,18 @@ void Network::convergent_connect(const std::vector & source_ids, const st "The connection will be ignored", source->get_gid(), target->get_gid()); if (!e.message().empty()) - msg += "\nDetails: " + e.message(); + msg += "\nDetails: " + e.message(); + message(SLIInterpreter::M_WARNING, "ConvergentConnect", msg.c_str()); + continue; + } + catch (TypeMismatch& e) + { + std::string msg = String::compose("In Connection from global source ID %1 to target ID %2: " + "Expect source and weights of type double. " + "The connection will be ignored", + source->get_gid(), target->get_gid()); + if (!e.message().empty()) + msg += "\nDetails: " + e.message(); message(SLIInterpreter::M_WARNING, "ConvergentConnect", msg.c_str()); continue; } @@ -1393,6 +1565,8 @@ void Network::random_convergent_connect(const TokenArray source_ids, index targe if (!is_local_gid(target_id)) return; + force_preparation(); + Node* target = get_node(target_id); // check if we have consistent lists for weights and delays @@ -1405,7 +1579,7 @@ void Network::random_convergent_connect(const TokenArray source_ids, index targe Subnet *target_comp=dynamic_cast(target); if(target_comp !=0) { - message(SLIInterpreter::M_INFO, "RandomConvergentConnect","Target ID is a subnet; I will iterate it."); + message(SLIInterpreter::M_INFO, "RandomConvergentConnect", "Target ID is a subnet; I will iterate it."); // we only consider local leaves as targets, LocalLeafList target_nodes(*target_comp); @@ -1443,11 +1617,11 @@ void Network::random_convergent_connect(const TokenArray source_ids, index targe convergent_connect(chosen_sources, target_id, weights, delays, syn); } - +// This function loops over all targets, with every thread taking +// care only of its own target nodes void Network::random_convergent_connect(TokenArray source_ids, TokenArray target_ids, TokenArray ns, TokenArray weights, TokenArray delays, bool allow_multapses, bool allow_autapses, index syn) { - // This function loops over all targets, with every thread taking - // care only of his own target nodes + force_preparation(); #ifndef _OPENMP // It only makes sense to call this function if we have openmp @@ -1478,19 +1652,44 @@ void Network::random_convergent_connect(TokenArray source_ids, TokenArray target message(SLIInterpreter::M_ERROR, "ConvergentConnect", "weights, delays and ns must be same size."); throw DimensionMismatch(); } - - bool abort = false; + + for(size_t i = 0; i < ns.size(); ++i) + { + size_t n; + // This throws std::bad_cast if the dynamic_cast goes + // wrong. Throwing in a parallel section is not allowed. This + // could be solved by only accepting IntVectorDatums for the ns. + try { + const IntegerDatum& nid = dynamic_cast(*ns.get(i)); + n = nid.get(); + } catch (const std::bad_cast& e) { + message(SLIInterpreter::M_ERROR, "ConvergentConnect", "ns must consist of integers only."); + throw KernelException(); + } + + // Check if we have consistent lists for weights and delays part two. + // The inner lists have to be equal to n or be zero. + if (weights.size() > 0) + { + TokenArray ws = getValue(weights.get(i)); + TokenArray ds = getValue(delays.get(i)); + + if (! (ws.size() == n || ws.size() == 0) && (ws.size() == ds.size())) + { + message(SLIInterpreter::M_ERROR, "ConvergentConnect", "weights and delays must be lists of size n."); + throw DimensionMismatch(); + } + } + } #pragma omp parallel { int nrn_counter = 0; - int tid = 0; - - tid = omp_get_thread_num(); + int tid = omp_get_thread_num(); librandom::RngPtr rng = get_rng(tid); - for (size_t i=0; i < target_ids.size() && !abort; i++) + for (size_t i=0; i < target_ids.size(); i++) { index target_id = target_ids.get(i); @@ -1506,12 +1705,11 @@ void Network::random_convergent_connect(TokenArray source_ids, TokenArray target nrn_counter++; - // TODO: This throws std::bad_cast if the dynamic_cast goes - // wrong. Throwing in a parallel section is not allowed. This - // could be solved by only accepting IntVectorDatums for the ns. + // extract number of connections for target i const IntegerDatum& nid = dynamic_cast(*ns.get(i)); const size_t n = nid.get(); + // extract weights and delays for all connections to target i TokenArray ws; TokenArray ds; if (weights.size() > 0) @@ -1520,16 +1718,6 @@ void Network::random_convergent_connect(TokenArray source_ids, TokenArray target ds = getValue(delays.get(i)); } - // Check if we have consistent lists for weights and delays - // We don't use omp flush here, as that would be a performance - // problem. As we just toggle a boolean variable, it does not - // matter in which order this happens and if multiple threads - // are doing this concurrently. - // TODO: Check the dimensions of all parameters already before - // the beginning of the parallel section - if (! (ws.size() == n || ws.size() == 0) && (ws.size() == ds.size()) && !abort) - abort = true; - vector chosen_sources(n); vector chosen_source_ids(n); std::set ch_ids; @@ -1558,19 +1746,46 @@ void Network::random_convergent_connect(TokenArray source_ids, TokenArray target } // of for all targets } // of omp parallel +#endif +} - // TODO: Move this exception throwing block and the check for - // consistent weight and delay lists above from inside the parallel - // section to outside. - if (abort) + void Network::connect(const GIDCollection& sources, + const GIDCollection& targets, + const DictionaryDatum& conn_spec, + const DictionaryDatum& syn_spec) { - message(SLIInterpreter::M_ERROR, "ConvergentConnect", "weights and delays must be lists of size n."); - throw DimensionMismatch(); - } + conn_spec->clear_access_flags(); + syn_spec->clear_access_flags(); -#endif + if ( !conn_spec->known(names::rule) ) + throw BadProperty("Connectivity spec must contain connectivity rule."); + const std::string rule_name = (*conn_spec)[names::rule]; -} + if ( !connruledict_->known(rule_name) ) + throw BadProperty("Unknown connectivty rule: " + rule_name); + const long rule_id = (*connruledict_)[rule_name]; + + ConnBuilder* cb = connbuilder_factories_.at(rule_id)->create(*this, + sources, + targets, + conn_spec, + syn_spec); + assert(cb != 0); + + // at this point, all entries in conn_spec and syn_spec have been checked + std::string missed; + if ( !(conn_spec->all_accessed(missed) && syn_spec->all_accessed(missed)) ) + { + if ( dict_miss_is_error() ) + throw UnaccessedDictionaryEntry(missed); + else + message(SLIInterpreter::M_WARNING, "Connect", + ("Unread dictionary entries: " + missed).c_str()); + } + + cb->connect(); + delete cb; + } void Network::message(int level, const char from[], const char text[]) { @@ -1671,6 +1886,8 @@ void Network::unregister_model(index m_id) void Network::try_unregister_model(index m_id) { + force_preparation(); + Model* m = get_model(m_id); // may throw UnknownModelID std::string name = m->get_name(); @@ -1711,24 +1928,24 @@ int Network::execute_sli_protected(DictionaryDatum state, Name cmd) #ifdef HAVE_MUSIC void Network::register_music_in_port(std::string portname) { - std::map< std::string, std::pair >::iterator it; + std::map< std::string, MusicPortData >::iterator it; it = music_in_portlist_.find(portname); if (it == music_in_portlist_.end()) - music_in_portlist_[portname] = std::pair(1, 0.0); + music_in_portlist_[portname] = MusicPortData (1, 0.0, -1); else - music_in_portlist_[portname].first++; + music_in_portlist_[portname].n_input_proxies++; } void Network::unregister_music_in_port(std::string portname) { - std::map< std::string, std::pair >::iterator it; + std::map< std::string, MusicPortData >::iterator it; it = music_in_portlist_.find(portname); if (it == music_in_portlist_.end()) throw MUSICPortUnknown(portname); else - music_in_portlist_[portname].first--; + music_in_portlist_[portname].n_input_proxies--; - if (music_in_portlist_[portname].first == 0) + if (music_in_portlist_[portname].n_input_proxies == 0) music_in_portlist_.erase(it); } @@ -1738,7 +1955,10 @@ void Network::register_music_event_in_proxy(std::string portname, int channel, n it = music_in_portmap_.find(portname); if (it == music_in_portmap_.end()) { - MusicEventHandler tmp(portname, music_in_portlist_[portname].second, this); + MusicEventHandler tmp(portname, + music_in_portlist_[portname].acceptable_latency, + music_in_portlist_[portname].max_buffered, + this); tmp.register_channel(channel, mp); music_in_portmap_[portname] = tmp; } @@ -1748,12 +1968,22 @@ void Network::register_music_event_in_proxy(std::string portname, int channel, n void Network::set_music_in_port_acceptable_latency(std::string portname, double latency) { - std::map< std::string, std::pair >::iterator it; + std::map< std::string, MusicPortData >::iterator it; + it = music_in_portlist_.find(portname); + if (it == music_in_portlist_.end()) + throw MUSICPortUnknown(portname); + else + music_in_portlist_[portname].acceptable_latency = latency; +} + +void Network::set_music_in_port_max_buffered(std::string portname, int_t maxbuffered) +{ + std::map< std::string, MusicPortData >::iterator it; it = music_in_portlist_.find(portname); if (it == music_in_portlist_.end()) throw MUSICPortUnknown(portname); else - music_in_portlist_[portname].second = latency; + music_in_portlist_[portname].max_buffered = maxbuffered; } void Network::publish_music_in_ports_() diff --git a/nestkernel/network.h b/nestkernel/network.h index 5f8514a1bb..8274263071 100644 --- a/nestkernel/network.h +++ b/nestkernel/network.h @@ -47,6 +47,10 @@ #undef M_ERROR #endif +#ifdef _OPENMP +#include +#endif + #ifdef HAVE_MUSIC #include "music_event_handler.h" #endif @@ -64,6 +68,8 @@ namespace nest class SiblingContainer; class Event; class Node; + class GenericConnBuilderFactory; + class GIDCollection; /** * @defgroup network Network access and administration @@ -108,6 +114,8 @@ Name: kernel - Global properties of the simulation kernel. network_size integertype - The number of nodes in the network num_connections integertype - The number of connections in the network num_processes integertype - The number of MPI processes + num_rec_processes integertype - The number of MPI processes reserved for recording spikes + num_sim_processes integertype - The number of MPI processes reserved for simulating neurons off_grid_spiking booltype - Whether to transmit precise spike times in MPI communicatio overwrite_files booltype - Whether to overwrite existing data files print_time booltype - Whether to print progress information during the simulation @@ -215,6 +223,12 @@ SeeAlso: Simulate, Node */ int copy_synapse_prototype(index sc, std::string); + /** + * Add a connectivity rule, i.e. the respective ConnBuilderFactory. + */ + template + void register_conn_builder(const std::string& name); + /** * Return the model id for a given model name. */ @@ -280,25 +294,69 @@ SeeAlso: Simulate, Node /** * Connect two nodes. The two nodes are defined by their global IDs. + * The source node is defined by its global ID. + * The target node is defined by its gloabl ID and the node. * The connection is established on the thread/process that owns the * target node. - * \param s Address of the sending Node. - * \param r Address of the receiving Node. + * \param s GID of the sending Node. + * \param t GID of the receiving Node. + * \param target pointer to target Node. + * \param target_thread thread that hosts the target node + * \param w Weight of the connection. + * \param d Delay of the connection (in ms). * \param syn The synapse model to use. - */ - void connect(index s, index r, index syn); + */ + void connect(index s, index t, Node* target, thread target_thread, + double_t w, double_t d, index syn); /** * Connect two nodes. The two nodes are defined by their global IDs. + * The source node is defined by its global ID. + * The target node is defined by its gloabl ID and the node. * The connection is established on the thread/process that owns the * target node. - * \param s Address of the sending Node. - * \param r Address of the receiving Node. + * \param s GID of the sending Node. + * \param t GID of the receiving Node. + * \param target pointer to target Node. + * \param target_thread thread that hosts the target node + * \param syn The synapse model to use. + */ + void connect(index s, index t, Node* target, thread target_thread, + index syn); + + /** + * Connect two nodes. The two nodes are defined by their global IDs. + * The source node is defined by its global ID. + * The target node is defined by its gloabl ID and the node. + * The connection is established on the thread/process that owns the + * target node. + * \param s GID of the sending Node. + * \param t GID of the receiving Node. + * \param target pointer to target Node. + * \param target_thread thread that hosts the target node * \param w Weight of the connection. * \param d Delay of the connection (in ms). + * \param params parameter dict t configure the synapse * \param syn The synapse model to use. - */ - void connect(index s, index r, double_t w, double_t d, index syn); + */ + void connect(index s, index t, Node* target, thread target_thread, + double_t w, double_t d, DictionaryDatum& params, index syn); + + /** + * Connect two nodes. The two nodes are defined by their global IDs. + * The source node is defined by its global ID. + * The target node is defined by its gloabl ID and the node. + * The connection is established on the thread/process that owns the + * target node. + * \param s GID of the sending Node. + * \param t GID of the receiving Node. + * \param target pointer to target Node. + * \param target_thread thread that hosts the target node + * \param params parameter dict t configure the synapse + * \param syn The synapse model to use. + */ + void connect(index s, index t, Node* target, thread target_thread, + DictionaryDatum& params, index syn); /** * Connect two nodes. The two nodes are defined by their global IDs. @@ -329,10 +387,15 @@ SeeAlso: Simulate, Node */ void divergent_connect(index s, DictionaryDatum d, index syn); + void random_divergent_connect(index s, const TokenArray r, index n, const TokenArray w, const TokenArray d, bool, bool, index syn); void convergent_connect(const TokenArray s, index r, const TokenArray weights, const TokenArray delays, index syn); + /** + * Specialized version of convegent_connect + * called by random_convergent_connect threaded + */ void convergent_connect(const std::vector &s_id, const std::vector &s, index r, const TokenArray &weight, const TokenArray &delays, index syn); void random_convergent_connect(const TokenArray s, index t, index n, const TokenArray w, const TokenArray d, bool, bool, index syn); @@ -342,6 +405,12 @@ SeeAlso: Simulate, Node * Parallelize over target list. */ void random_convergent_connect(TokenArray s, TokenArray t, TokenArray n, TokenArray w, TokenArray d, bool, bool, index syn); + + /** + * Create connections. + */ + void connect(const GIDCollection&, const GIDCollection&, + const DictionaryDatum&, const DictionaryDatum&); DictionaryDatum get_connector_defaults(index sc); void set_connector_defaults(index sc, DictionaryDatum& d); @@ -372,6 +441,16 @@ SeeAlso: Simulate, Node */ void resume(); + /** + * Force re-preparation of the simulation. + * This function must be called to re-create the simulation buffers when + * - new neurons have been created + * - new connections have been created + * - the number of threads changes + * - the temporal resolution changes. + */ + void force_preparation(); + /** * Terminate the simulation after the time-slice is finished. */ @@ -467,6 +546,11 @@ SeeAlso: Simulate, Node * Suggest a VP for a given global node ID */ thread suggest_vp(index) const; + + /** + * Suggest a VP for a given global recording node ID + */ + thread suggest_rec_vp(index) const; /** * Convert a given VP ID to the corresponding thread ID @@ -483,6 +567,21 @@ SeeAlso: Simulate, Node */ thread get_num_processes() const; + /** + * Get number of recording processes. + */ + thread get_num_rec_processes() const; + + /** + * Get number of simulating processes. + */ + thread get_num_sim_processes() const; + + /** + * Set number of recording processes. + */ + void set_num_rec_processes(int nrp); + /** * Return true, if the given Node is on the local machine */ @@ -689,17 +788,28 @@ SeeAlso: Simulate, Node * Set the acceptable latency (latency) for a music input port (portname). */ void set_music_in_port_acceptable_latency(std::string portname, double_t latency); + void set_music_in_port_max_buffered(std::string portname, int_t maxbuffered); + /** + * Data structure to hold variables and parameters associated with a port. + */ + struct MusicPortData { + MusicPortData (size_t n, double_t latency, int_t m) + : n_input_proxies (n), acceptable_latency (latency), max_buffered (m) + { } + MusicPortData () { } + size_t n_input_proxies; // Counter for number of music_input proxies + // connected to this port + double_t acceptable_latency; + int_t max_buffered; + }; /** * The mapping between MUSIC input ports identified by portname - * and the corresponding acceptable latency (second component of - * the pair). The first component of the pair is a counter that is - * used to track how many music_input_proxies are connected to the - * port. + * and the corresponding port variables and parameters. * @see register_music_in_port() * @see unregister_music_in_port() */ - std::map< std::string, std::pair > music_in_portlist_; + std::map< std::string, MusicPortData > music_in_portlist_; /** * The mapping between MUSIC input ports identified by portname @@ -719,11 +829,20 @@ SeeAlso: Simulate, Node */ void update_music_event_handlers_(Time const &, const long_t, const long_t); #endif - + + /** + * Gets ID of local thread. + * Returns thread ID if OPENMP is installed + * and zero otherwise. + */ + int get_thread_id() const; + + void create_thread_local_ids(); private: void connect(Node& s, Node& r, index sgid, thread t, index syn); void connect(Node& s, Node& r, index sgid, thread t, double_t w, double_t d, index syn); void connect(Node& s, Node& r, index sgid, thread t, DictionaryDatum& d, index syn); + void connect(Node& s, Node& r, index sgid, thread t, double_t w, double_t d, DictionaryDatum& p, index syn); /** * Initialize the network data structures. @@ -732,7 +851,7 @@ SeeAlso: Simulate, Node */ void init_(); void destruct_nodes_(); - void clear_models_(); + void clear_models_(bool called_from_destructor=false); /** * Helper function to set properties on single node. @@ -772,6 +891,16 @@ SeeAlso: Simulate, Node */ Dictionary* modeldict_; //!< Dictionary for models. + /* BeginDocumentation + Name: connruledict - dictionary containing all connectivity rules + Description: + This dictionary provides the connection rules that can be used + in Connect. + 'connruledict info' shows the contents of the dictionary. + SeeAlso: Connect + */ + Dictionary* connruledict_; //!< Dictionary for connection rules. + Model* siblingcontainer_model; //!< The model for the SiblingContainer class std::string data_path_; //!< Path for all files written by devices @@ -787,6 +916,10 @@ SeeAlso: Simulate, Node std::vector< std::pair > pristine_models_; std::vector models_; //!< The list of available models + + //! ConnBuilder factories, indexed by connruledict_ elements. + std::vector connbuilder_factories_; + std::vector proxy_nodes_; //!< Placeholders for remote nodes, one per thread std::vector dummy_spike_sources_; //!< Placeholders for spiking remote nodes, one per thread @@ -830,24 +963,35 @@ SeeAlso: Simulate, Node inline void Network::connect(Node& s, Node& r, index sgid, thread t, index syn) { + force_preparation(); connection_manager_.connect(s, r, sgid, t, syn); } inline void Network::connect(Node& s, Node& r, index sgid, thread t, double_t w, double_t d, index syn) { + force_preparation(); connection_manager_.connect(s, r, sgid, t, w, d, syn); } inline void Network::connect(Node& s, Node& r, index sgid, thread t, DictionaryDatum& p, index syn) { + force_preparation(); connection_manager_.connect(s, r, sgid, t, p, syn); } + inline + void Network::connect(Node& s, Node& r, index sgid, thread t, double_t w, double_t d, DictionaryDatum& params, index syn) + { + force_preparation(); + connection_manager_.connect(s, r, sgid, t, w, d, params, syn); + } + inline void Network::connect(ArrayDatum &connectome) { + force_preparation(); connection_manager_.connect(connectome); } @@ -976,6 +1120,24 @@ SeeAlso: Simulate, Node { return scheduler_.get_num_processes(); } + + inline + thread Network::get_num_rec_processes() const + { + return scheduler_.get_num_rec_processes(); + } + + inline + thread Network::get_num_sim_processes() const + { + return scheduler_.get_num_sim_processes(); + } + + inline + void Network::set_num_rec_processes(int nrp) + { + scheduler_.set_num_rec_processes(nrp); + } inline bool Network::is_local_node(Node* n) const @@ -1005,6 +1167,12 @@ SeeAlso: Simulate, Node { return scheduler_.suggest_vp(gid); } + + inline + int Network::suggest_rec_vp(index gid) const + { + return scheduler_.suggest_rec_vp(gid); + } inline thread Network::vp_to_thread(thread vp) const @@ -1057,8 +1225,6 @@ SeeAlso: Simulate, Node thread t = source.get_thread(); index gid = source.get_gid(); - //std::cout << "Network::send 1 " << gid << " " << e.get_sender().get_gid() << std::endl; - assert(!source.has_proxies()); connection_manager_.send(t, gid, e); } @@ -1236,6 +1402,22 @@ SeeAlso: Simulate, Node } }; + inline + void Network::force_preparation() + { + scheduler_.force_preparation(); + } + + inline + int Network::get_thread_id() const + { +#ifdef _OPENMP + return omp_get_thread_num(); +#else + return 0; +#endif + } + } // namespace #endif diff --git a/nestkernel/network_impl.h b/nestkernel/network_impl.h new file mode 100644 index 0000000000..50e16cdfe3 --- /dev/null +++ b/nestkernel/network_impl.h @@ -0,0 +1,42 @@ +/* + * network_impl.h + * + * This file is part of NEST. + * + * Copyright (C) 2004 The NEST Initiative + * + * NEST 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 2 of the License, or + * (at your option) any later version. + * + * NEST 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 NEST. If not, see . + * + */ + +#ifndef NETWORK_IMPL_H +#define NETWORK_IMPL_H + +#include "network.h" +#include "conn_builder.h" +#include "conn_builder_factory.h" + +template +void nest::Network::register_conn_builder(const std::string& name) +{ + assert(!connruledict_->known(name)); + GenericConnBuilderFactory* cb = new ConnBuilderFactory(); + assert(cb != 0); + const int id = connbuilder_factories_.size(); + connbuilder_factories_.push_back(cb); + connruledict_->insert(name, id); +} + +#endif + diff --git a/nestkernel/node.cpp b/nestkernel/node.cpp index 40cdb4ff60..8f4e0efefe 100644 --- a/nestkernel/node.cpp +++ b/nestkernel/node.cpp @@ -171,10 +171,12 @@ namespace nest { else unset(frozen); } + if(net_) + net_->force_preparation(); // re-prepeare simulation } /** - * Default implementation of just throws UnexpectedEvent + * Default implementation of check_connection just throws UnexpectedEvent */ port Node::check_connection(Connection&, port) { @@ -296,6 +298,15 @@ namespace nest { throw UnexpectedEvent(); } + void Node::set_has_proxies(const bool) + { + throw UnexpectedEvent(); + } + + void Node::set_local_receiver(const bool) + { + throw UnexpectedEvent(); + } void Node::event_hook(DSSpikeEvent& e) { diff --git a/nestkernel/node.h b/nestkernel/node.h index cbcf9213e2..79c8a381a6 100644 --- a/nestkernel/node.h +++ b/nestkernel/node.h @@ -155,6 +155,21 @@ namespace nest { */ virtual bool has_proxies() const; + /** + * Returns true for potential global receivers (e.g. spike_detector) and false otherwise + */ + virtual bool potential_global_receiver() const; + + /** + * Sets has_proxies_ member variable (to switch to global spike detection mode) + */ + virtual void set_has_proxies(const bool); + + /** + * Sets local_receiver_ member variable (to switch to global spike detection mode) + */ + virtual void set_local_receiver(const bool); + /** * Returns true if the node only receives events from nodes/devices * on the same thread. @@ -195,7 +210,6 @@ namespace nest { virtual void register_connector(nest::Connector&) {} - /** * Return global Network ID. * Returns the global network ID of the Node. @@ -426,7 +440,6 @@ namespace nest { * @see Event */ - /** * This function checks if the receiver accepts the connection by creating an * instance of the event type it sends in its update() function and passing it @@ -844,6 +857,12 @@ namespace nest { return true; } + inline + bool Node::potential_global_receiver() const + { + return false; + } + inline bool Node::local_receiver() const { diff --git a/nestkernel/recordables_map.h b/nestkernel/recordables_map.h index 4e794816b1..5223e677d4 100644 --- a/nestkernel/recordables_map.h +++ b/nestkernel/recordables_map.h @@ -1,6 +1,3 @@ -#ifndef RECORDABLES_MAP_H -#define RECORDABLES_MAP_H - /* * recordables_map.h * @@ -23,6 +20,9 @@ * */ +#ifndef RECORDABLES_MAP_H +#define RECORDABLES_MAP_H + #include #include #include diff --git a/nestkernel/recording_device.cpp b/nestkernel/recording_device.cpp index 6de5ef4578..12474973ca 100644 --- a/nestkernel/recording_device.cpp +++ b/nestkernel/recording_device.cpp @@ -360,10 +360,8 @@ nest::RecordingDevice::RecordingDevice(const Node& n, Mode mode, const std::stri std::string newname = build_filename_(); if ( newname != P_.filename_ ) { - Node::network()->message(SLIInterpreter::M_INFO, - "RecordingDevice::calibrate()", - "Closing file " + P_.filename_ + - ", opening file " + newname); + std::string msg = String::compose("Closing file '%1', opening file '%2'", P_.filename_, newname); + Node::network()->message(SLIInterpreter::M_INFO, "RecordingDevice::calibrate()", msg); B_.fs_.close(); // close old file P_.filename_ = newname; @@ -388,9 +386,10 @@ nest::RecordingDevice::RecordingDevice(const Node& n, Mode mode, const std::stri std::ifstream test(P_.filename_.c_str()); if ( test.good() ) { - Node::network()->message(SLIInterpreter::M_ERROR, "RecordingDevice::calibrate()", - "The device file " + P_.filename_ + " exists already and will not be overwritten.\n" - "Please change data_path, data_prefix or label, or set /overwrite_files to true in the root node." ); + std::string msg = String::compose("The device file '%1' exists already and will not be overwritten. " + "Please change data_path, data_prefix or label, or set /overwrite_files " + "to true in the root node.",P_.filename_); + Node::network()->message(SLIInterpreter::M_ERROR, "RecordingDevice::calibrate()", msg); throw IOError(); } else @@ -419,8 +418,11 @@ nest::RecordingDevice::RecordingDevice(const Node& n, Mode mode, const std::stri if ( !B_.fs_.good() ) { - Node::network()->message(SLIInterpreter::M_ERROR, "RecordingDevice::calibrate()", - "I/O error while opening file " + P_.filename_); + std::string msg = String::compose("I/O error while opening file '%1'. " + "This may be caused by too many open files in networks " + "with many recording devices and threads.", P_.filename_); + Node::network()->message(SLIInterpreter::M_ERROR, "RecordingDevice::calibrate()", msg); + if ( B_.fs_.is_open() ) B_.fs_.close(); P_.filename_.clear(); @@ -466,8 +468,9 @@ nest::RecordingDevice::RecordingDevice(const Node& n, Mode mode, const std::stri if ( !B_.fs_.good() ) { - Node::network()->message(SLIInterpreter::M_ERROR, "RecordingDevice::finalize()", - "I/O error while writing to file " + P_.filename_); + std::string msg = String::compose("I/O error while opening file '%1'",P_.filename_); + Node::network()->message(SLIInterpreter::M_ERROR, "RecordingDevice::finalize()", msg); + throw IOError(); } } diff --git a/nestkernel/scheduler.cpp b/nestkernel/scheduler.cpp index 2a5f274353..1d6356f598 100644 --- a/nestkernel/scheduler.cpp +++ b/nestkernel/scheduler.cpp @@ -54,6 +54,7 @@ #include "arraydatum.h" #include "randomgen.h" #include "random_datums.h" +#include "gslrandomgen.h" #include "nest_timemodifier.h" #include "nest_timeconverter.h" @@ -78,6 +79,7 @@ nest::Scheduler::Scheduler(Network &net) force_singlethreading_(false), n_threads_(1), n_nodes_(0), + n_rec_procs_(0), entry_counter_(0), exit_counter_(0), net_(net), @@ -89,6 +91,7 @@ nest::Scheduler::Scheduler(Network &net) to_step_(0L), // consistent with to_do_ == 0 update_ref_(true), terminate_(false), + is_prepared_(false), off_grid_spiking_(false), print_time_(false), rng_() @@ -107,12 +110,11 @@ void nest::Scheduler::reset() // See ticket #217 for details. nest::TimeModifier::reset_to_defaults(); - clock_.set_to_zero(); // ensures consistent state + clock_.set_to_zero(); // ensures consistent state to_do_ = 0; slice_ = 0; from_step_ = 0; - to_step_ = 0; // consistent with to_do_ = 0 - + to_step_ = 0; // consistent with to_do_ = 0 finalize_(); init_(); } @@ -127,6 +129,7 @@ void nest::Scheduler::init_() assert(initialized_ == false); simulated_ = false; + is_prepared_=false; min_delay_ = max_delay_ = 0; update_ref_ = true; @@ -135,7 +138,7 @@ void nest::Scheduler::init_() if(status != 0) { net_.message(SLIInterpreter::M_ERROR, "Scheduler::reset", - "Error initializing condition variable done_"); + "Error initializing condition variable done_"); throw PthreadException(status); } @@ -143,7 +146,7 @@ void nest::Scheduler::init_() if(status != 0) { net_.message(SLIInterpreter::M_ERROR, "Scheduler::reset", - "Error initializing condition variable ready_"); + "Error initializing condition variable ready_"); throw PthreadException(status); } #else @@ -151,7 +154,7 @@ void nest::Scheduler::init_() if (n_threads_ > 1) { net_.message(SLIInterpreter::M_ERROR, "Scheduler::reset", - "No multithreading available, using single threading"); + "No multithreading available, using single threading"); n_threads_ = 1; force_singlethreading_ = true; } @@ -160,20 +163,23 @@ void nest::Scheduler::init_() set_num_threads(n_threads_); - create_rngs_(true); // flag that this is a call from the ctr - create_grng_(true); // flag that this is a call from the ctr + n_sim_procs_ = Communicator::get_num_processes()-n_rec_procs_; + + create_rngs_(true); // flag that this is a call from the ctr + create_grng_(true); // flag that this is a call from the ctr initialized_ = true; } void nest::Scheduler::finalize_() { + #ifdef HAVE_PTHREADS int status = pthread_cond_destroy(&done_); if(status != 0) { net_.message(SLIInterpreter::M_ERROR, "Scheduler::reset", - "Error in destruction of condition variable done_"); + "Error in destruction of condition variable done_"); throw PthreadException(status); } @@ -181,7 +187,7 @@ void nest::Scheduler::finalize_() if(status != 0) { net_.message(SLIInterpreter::M_ERROR, "Scheduler::reset", - "Error in destruction of condition variable ready_"); + "Error in destruction of condition variable ready_"); throw PthreadException(status); } #endif @@ -197,8 +203,8 @@ void nest::Scheduler::finalize_() void nest::Scheduler::init_moduli_() { - assert (min_delay_ != 0); - assert (max_delay_ != 0); + assert(min_delay_ != 0); + assert(max_delay_ != 0); /* * Ring buffers use modulos to determine where to store incoming events @@ -209,16 +215,17 @@ void nest::Scheduler::init_moduli_() moduli_.resize(min_delay_ + max_delay_); - for(delay d=0; d < min_delay_ + max_delay_; ++d) - moduli_[d]= ( clock_.get_steps()+ d ) % (min_delay_ + max_delay_); + for (delay d = 0; d < min_delay_ + max_delay_; ++d) + moduli_[d] = (clock_.get_steps() + d) % (min_delay_ + max_delay_); // Slice-based ring-buffers have one bin per min_delay steps, // up to max_delay. Time is counted as for normal ring buffers. // The slice_moduli_ table maps time steps to these bins - const size_t nbuff = static_cast(std::ceil(static_cast(min_delay_+max_delay_) / min_delay_)); - slice_moduli_.resize(min_delay_+max_delay_); - for ( delay d = 0 ; d < min_delay_+max_delay_ ; ++d ) - slice_moduli_[d] = ( (clock_.get_steps() + d) / min_delay_ ) % nbuff; + const size_t nbuff = static_cast(std::ceil( + static_cast(min_delay_ + max_delay_) / min_delay_)); + slice_moduli_.resize(min_delay_ + max_delay_); + for (delay d = 0; d < min_delay_ + max_delay_; ++d) + slice_moduli_[d] = ((clock_.get_steps() + d) / min_delay_) % nbuff; } /** @@ -231,26 +238,28 @@ void nest::Scheduler::init_moduli_() */ void nest::Scheduler::compute_moduli_() { - assert (min_delay_ != 0); - assert (max_delay_ != 0); + assert(min_delay_ != 0); + assert(max_delay_ != 0); /* * Note that for updating the modulos, it is sufficient * to rotate the buffer to the left. */ assert(moduli_.size() == min_delay_ + max_delay_); - std::rotate(moduli_.begin(),moduli_.begin()+min_delay_,moduli_.end()); + std::rotate(moduli_.begin(), moduli_.begin() + min_delay_, moduli_.end()); /* For the slice-based ring buffer, we cannot rotate the table, but - have to re-compute it, since max_delay_ may not be a multiple of - min_delay_. Reference time is the time at the beginning of the slice. - */ - const size_t nbuff = static_cast(std::ceil(static_cast(min_delay_+max_delay_) / min_delay_)); - for ( delay d = 0 ; d < min_delay_+max_delay_ ; ++d ) - slice_moduli_[d] = ((clock_.get_steps() + d) / min_delay_ ) % nbuff; + have to re-compute it, since max_delay_ may not be a multiple of + min_delay_. Reference time is the time at the beginning of the slice. + */ + const size_t nbuff = static_cast(std::ceil( + static_cast(min_delay_ + max_delay_) / min_delay_)); + for (delay d = 0; d < min_delay_ + max_delay_; ++d) + slice_moduli_[d] = ((clock_.get_steps() + d) / min_delay_) % nbuff; } -void nest::Scheduler::compute_delay_extrema_(delay& min_delay, delay& max_delay) const +void nest::Scheduler::compute_delay_extrema_(delay& min_delay, + delay& max_delay) const { min_delay = net_.connection_manager_.get_min_delay().get_steps(); max_delay = net_.connection_manager_.get_max_delay().get_steps(); @@ -267,6 +276,9 @@ void nest::Scheduler::compute_delay_extrema_(delay& min_delay, delay& max_delay) Communicator::communicate(max_delays); max_delay = *std::max_element(max_delays.begin(), max_delays.end()); } + + if (min_delay == Time::pos_inf().get_steps()) + min_delay = Time::get_resolution().get_steps(); } void nest::Scheduler::configure_spike_buffers_() @@ -275,20 +287,23 @@ void nest::Scheduler::configure_spike_buffers_() spike_register_.clear(); // the following line does not compile with gcc <= 3.3.5 - spike_register_.resize(n_threads_, std::vector >(min_delay_)); + spike_register_.resize(n_threads_, + std::vector >(min_delay_)); for (size_t j = 0; j < spike_register_.size(); ++j) - for (size_t k = 0; k < spike_register_[j].size(); ++k) - spike_register_[j][k].clear(); + for (size_t k = 0; k < spike_register_[j].size(); ++k) + spike_register_[j][k].clear(); offgrid_spike_register_.clear(); // the following line does not compile with gcc <= 3.3.5 - offgrid_spike_register_.resize(n_threads_, std::vector >(min_delay_)); + offgrid_spike_register_.resize(n_threads_, + std::vector >(min_delay_)); for (size_t j = 0; j < offgrid_spike_register_.size(); ++j) - for (size_t k = 0; k < offgrid_spike_register_[j].size(); ++k) - offgrid_spike_register_[j][k].clear(); + for (size_t k = 0; k < offgrid_spike_register_[j].size(); ++k) + offgrid_spike_register_[j][k].clear(); //send_buffer must be >= 2 as the 'overflow' signal takes up 2 spaces. - int send_buffer_size = n_threads_ * min_delay_ > 2 ? n_threads_ * min_delay_ : 2; + int send_buffer_size = + n_threads_ * min_delay_ > 2 ? n_threads_ * min_delay_ : 2; int recv_buffer_size = send_buffer_size * Communicator::get_num_processes(); Communicator::set_buffer_sizes(send_buffer_size, recv_buffer_size); @@ -296,11 +311,11 @@ void nest::Scheduler::configure_spike_buffers_() local_grid_spikes_.clear(); local_grid_spikes_.resize(send_buffer_size, 0U); local_offgrid_spikes_.clear(); - local_offgrid_spikes_.resize(send_buffer_size, OffGridSpike(0,0.0)); + local_offgrid_spikes_.resize(send_buffer_size, OffGridSpike(0, 0.0)); global_grid_spikes_.clear(); global_grid_spikes_.resize(recv_buffer_size, 0U); global_offgrid_spikes_.clear(); - global_offgrid_spikes_.resize(recv_buffer_size, OffGridSpike(0,0.0)); + global_offgrid_spikes_.resize(recv_buffer_size, OffGridSpike(0, 0.0)); displacements_.clear(); displacements_.resize(Communicator::get_num_processes(), 0); @@ -309,10 +324,11 @@ void nest::Scheduler::configure_spike_buffers_() void nest::Scheduler::clear_nodes_vec_() { nodes_vec_.resize(n_threads_); - for(index t = 0; t < n_threads_; ++t) + for (index t = 0; t < n_threads_; ++t) nodes_vec_[t].clear(); } + void nest::Scheduler::simulate(Time const & t) { assert(initialized_); @@ -326,109 +342,86 @@ void nest::Scheduler::simulate(Time const & t) if (t < Time::step(1)) { - net_.message(SLIInterpreter::M_ERROR, "Scheduler::simulate", - String::compose("Simulation time must be >= %1 ms (one time step).", - Time::get_resolution().get_ms())); + net_.message( + SLIInterpreter::M_ERROR, + "Scheduler::simulate", + String::compose("Simulation time must be >= %1 ms (one time step).", + Time::get_resolution().get_ms())); throw KernelException(); } - // Check for synchronicity of global rngs over processes - if(Communicator::get_num_processes() > 1) - if (!Communicator::grng_synchrony(grng_->ulrand(100000))) - { - net_.message(SLIInterpreter::M_ERROR, "Scheduler::simulate", - "Global Random Number Generators are not synchronized prior to simulation."); - throw KernelException(); - } - - // As default, we have to place the iterator at the - // leftmost node of the tree. - // If the iteration process was suspended, we leave the - // iterator where it was and continue the iteration - // process by calling "resume()" - - // Note that the time argument accumulates. - // This is needed so that the following two - // calling sequences yield the same results: - // a: net.simulate(t1); // suspend is called here - // net.simulate(t2); - // assert(net.t == t1+t2); - // b: net.simulate(t1); // NO suspend called - // net.simulate(t2); - // assert(net.t == t1+t2); - // The philosophy behind this behaviour is that the user - // can in principle not know whether an element will suspend - // the cycle. - - // check whether the simulation clock - // will overflow during the simulation. - if ( t.is_finite() ) + if (t.is_finite()) { Time time1 = clock_ + t; - if( !time1.is_finite() ) - { - std::string msg = String::compose("A clock overflow will occur after %1 of %2 ms. Please reset network " - "clock first!", (Time::max()-clock_).get_ms(), t.get_ms()); - net_.message(SLIInterpreter::M_ERROR, "Scheduler::simulate", msg); - throw KernelException(); - } + if (!time1.is_finite()) + { + std::string msg = String::compose("A clock overflow will occur after %1 of %2 ms. Please reset network " + "clock first!", (Time::max()-clock_).get_ms(), t.get_ms()); + net_.message(SLIInterpreter::M_ERROR, "Scheduler::simulate", msg); + throw KernelException(); + } } else { std::string msg = String::compose("The requested simulation time exceeds the largest time NEST can handle " - "(T_max = %1 ms). Please use a shorter time!", Time::max().get_ms()); + "(T_max = %1 ms). Please use a shorter time!", Time::max().get_ms()); net_.message(SLIInterpreter::M_ERROR, "Scheduler::simulate", msg); throw KernelException(); } + to_do_ += t.get_steps(); to_do_total_ = to_do_; - - // find shortest and longest delay across all MPI processes - // this call sets the member variables - compute_delay_extrema_(min_delay_, max_delay_); - - // Warn about possible inconsistencies, see #504. - // This test cannot come any earlier, because we first need to compute min_delay_ - // above. - if ( t.get_steps() % min_delay_ != 0 ) - net_.message(SLIInterpreter::M_WARNING, "Scheduler::simulate", - "The requested simulation time is not an integer multiple of the minimal delay in the network. " - "This may result in inconsistent results under the following conditions: (i) A network contains " - "more than one source of randomness, e.g., two different poisson_generators, and (ii) Simulate " - "is called repeatedly with simulation times that are not multiples of the minimal delay."); + + prepare_simulation(); // from_step_ is not touched here. If we are at the beginning // of a simulation, it has been reset properly elsewhere. If // a simulation was ended and is now continued, from_step_ will // have the proper value. to_step_ is set as in advance_time(). + ulong_t end_sim = from_step_ + to_do_; if (min_delay_ < end_sim) to_step_ = min_delay_; // update to end of time slice else to_step_ = end_sim; // update to end of simulation time + // Warn about possible inconsistencies, see #504. + // This test cannot come any earlier, because we first need to compute min_delay_ + // above. + if (t.get_steps() % min_delay_ != 0) + net_.message( + SLIInterpreter::M_WARNING, + "Scheduler::simulate", + "The requested simulation time is not an integer multiple of the minimal delay in the network. " + "This may result in inconsistent results under the following conditions: (i) A network contains " + "more than one source of randomness, e.g., two different poisson_generators, and (ii) Simulate " + "is called repeatedly with simulation times that are not multiples of the minimal delay."); + + // We must recalibrate, since time constants and other neuronal parameters may + // have changed. resume(); - simulated_ = true; - - // Check for synchronicity of global rngs over processes - if(Communicator::get_num_processes() > 1) - if (!Communicator::grng_synchrony(grng_->ulrand(100000))) - { - net_.message(SLIInterpreter::M_ERROR, "Scheduler::simulate", - "Global Random Number Generators are not synchronized after simulation."); - throw KernelException(); - } } -void nest::Scheduler::resume() +void nest::Scheduler::prepare_simulation() { - assert(initialized_); + if(is_prepared_) + return; - terminate_ = false; + // std::cerr << "Preparing simulation\n"; - if(to_do_ == 0) - return; + // find shortest and longest delay across all MPI processes + // this call sets the member variables + compute_delay_extrema_(min_delay_, max_delay_); + + // Check for synchronicity of global rngs over processes + if(Communicator::get_num_processes() > 1) + if (!Communicator::grng_synchrony(grng_->ulrand(100000))) + { + net_.message(SLIInterpreter::M_ERROR, "Scheduler::simulate", + "Global Random Number Generators are not synchronized prior to simulation."); + throw KernelException(); + } #ifdef HAVE_PTHREAD_SETCONCURRENCY // The following is needed on Solaris 7 and higher @@ -445,7 +438,7 @@ void nest::Scheduler::resume() assert(threads_.size() == n_threads_); // if at the beginning of a simulation, set up spike buffers - if ( !simulated_ ) + if (!simulated_) configure_spike_buffers_(); prepare_nodes(); @@ -464,8 +457,38 @@ void nest::Scheduler::resume() Communicator::enter_runtime(tick); } #endif + is_prepared_= true; +} - simulating_ = true; +void nest::Scheduler::finalize_simulation() +{ + if(not simulated_) + return; + + // std::cerr << "Finalizing simulation\n"; + + // Check for synchronicity of global rngs over processes + if(Communicator::get_num_processes() > 1) + if (!Communicator::grng_synchrony(grng_->ulrand(100000))) + { + net_.message(SLIInterpreter::M_ERROR, "Scheduler::simulate", + "Global Random Number Generators are not synchronized after simulation."); + throw KernelException(); + } + + finalize_nodes(); + +} + +void nest::Scheduler::resume() +{ + assert(initialized_); + assert(is_prepared_); + + terminate_ = false; + + if(to_do_ == 0) + return; if (print_time_) { @@ -473,6 +496,8 @@ void nest::Scheduler::resume() print_progress_(); } + simulating_ = true; + if (n_threads_ == 1) serial_update(); else @@ -492,7 +517,7 @@ void nest::Scheduler::resume() threaded_update_openmp(); #else net_.message(SLIInterpreter::M_ERROR, "Scheduler::reset", - "No multithreading available, using single threading"); + "No multithreading available, using single threading"); serial_update(); #endif #endif @@ -504,16 +529,19 @@ void nest::Scheduler::resume() std::cout << std::endl; Communicator::synchronize(); + simulated_ = true; - if(terminate_) + if (terminate_) { - net_.message(SLIInterpreter::M_ERROR, "Scheduler::resume", "Exiting on error or user signal."); - net_.message(SLIInterpreter::M_ERROR, "Scheduler::resume", "Scheduler: Use 'ResumeSimulation' to resume."); + net_.message(SLIInterpreter::M_ERROR, "Scheduler::resume", + "Exiting on error or user signal."); + net_.message(SLIInterpreter::M_ERROR, "Scheduler::resume", + "Scheduler: Use 'ResumeSimulation' to resume."); - if(SLIsignalflag != 0) + if (SLIsignalflag != 0) { SystemSignal signal(SLIsignalflag); - SLIsignalflag=0; + SLIsignalflag = 0; throw signal; } else @@ -522,7 +550,8 @@ void nest::Scheduler::resume() return; } - net_.message(SLIInterpreter::M_INFO, "Scheduler::resume", "Simulation finished."); + net_.message(SLIInterpreter::M_INFO, "Scheduler::resume", + "Simulation finished."); } /** @@ -538,7 +567,7 @@ void nest::Scheduler::serial_update() if (print_time_) gettimeofday(&t_slice_begin_, NULL); - if ( from_step_ == 0 ) // deliver only at beginning of slice + if (from_step_ == 0) // deliver only at beginning of slice { deliver_events_(0); #ifdef HAVE_MUSIC @@ -556,15 +585,16 @@ void nest::Scheduler::serial_update() for (i = nodes_vec_[0].begin(); i != nodes_vec_[0].end(); ++i) update_(*i); - if ( static_cast(to_step_) == min_delay_ ) // gather only at end of slice + if (static_cast(to_step_) == min_delay_) // gather only at end of slice gather_events_(); advance_time_(); - if(SLIsignalflag != 0) + if (SLIsignalflag != 0) { - net_.message(SLIInterpreter::M_INFO, "Scheduler::serial_update", "Simulation exiting on user signal."); - terminate_=true; + net_.message(SLIInterpreter::M_INFO, "Scheduler::serial_update", + "Simulation exiting on user signal."); + terminate_ = true; } if (print_time_) @@ -572,9 +602,10 @@ void nest::Scheduler::serial_update() gettimeofday(&t_slice_end_, NULL); print_progress_(); } - } while((to_do_ != 0) && (! terminate_)); + } while ((to_do_ != 0) && (!terminate_)); } + void nest::Scheduler::threaded_update_openmp() { #ifdef _OPENMP @@ -589,27 +620,39 @@ void nest::Scheduler::threaded_update_openmp() t = omp_get_thread_num(); // which thread am I #endif - do { + do + { if (print_time_) gettimeofday(&t_slice_begin_, NULL); - if ( from_step_ == 0 ) // deliver only at beginning of slice - { - deliver_events_(t); + if (from_step_ == 0) // deliver only at beginning of slice + { + deliver_events_(t); #ifdef HAVE_MUSIC // advance the time of music by one step (min_delay * h) must // be done after deliver_events_() since it calls // music_event_out_proxy::handle(), which hands the spikes over to // MUSIC *before* MUSIC time is advanced - if (slice_ > 0) - Communicator::advance_music_time(1); - net_.update_music_event_handlers_(clock_, from_step_, to_step_); + // wait until all threads are done -> synchronize +#pragma omp barrier + + // the following block is executed by a single thread + // the other threads wait at the end of the block +#pragma omp single + { + if (slice_ > 0) + Communicator::advance_music_time(1); + + // the following could be made thread-safe + net_.update_music_event_handlers_(clock_, from_step_, to_step_); + } #endif } - for (std::vector::iterator i = nodes_vec_[t].begin(); i != nodes_vec_[t].end(); ++i) - update_(*i); + for (std::vector::iterator i = nodes_vec_[t].begin(); + i != nodes_vec_[t].end(); ++i) + update_(*i); // parallel section ends, wait until all threads are done -> synchronize #pragma omp barrier @@ -618,18 +661,19 @@ void nest::Scheduler::threaded_update_openmp() // the other threads wait at the end of the block #pragma omp single { - if ( static_cast(to_step_) == min_delay_ ) // gather only at end of slice - gather_events_(); + if (static_cast(to_step_) == min_delay_) // gather only at end of slice + gather_events_(); - advance_time_(); + advance_time_(); - if(SLIsignalflag != 0) - { - net_.message(SLIInterpreter::M_INFO, "Scheduler::serial_update", "Simulation exiting on user signal."); - terminate_ = true; - } + if (SLIsignalflag != 0) + { + net_.message(SLIInterpreter::M_INFO, "Scheduler::serial_update", + "Simulation exiting on user signal."); + terminate_ = true; + } - if (print_time_) + if (print_time_) { gettimeofday(&t_slice_end_, NULL); print_progress_(); @@ -638,7 +682,7 @@ void nest::Scheduler::threaded_update_openmp() // end of single section, all threads synchronize at this point } - while((to_do_ != 0) && (! terminate_)); + while ((to_do_ != 0) && (! terminate_)); } // end of #pragma parallel omp } @@ -706,7 +750,7 @@ void nest::Scheduler::threaded_update(thread t) //////////// Parallel section beyond this line // Deliver events and update all neurons in parallel - if ( from_step_ == 0 ) // deliver only at beginning of slice + if ( from_step_ == 0 ) // deliver only at beginning of slice { deliver_events_(t); @@ -733,7 +777,7 @@ void nest::Scheduler::threaded_update(thread t) //////////// Serial section beyond this line - ++exit_counter_; // Mark thread idle. + ++exit_counter_; // Mark thread idle. // We are at the end of a time slice or the end of simulation time, // which may be inside a time slice. @@ -781,7 +825,7 @@ void nest::Scheduler::threaded_update(thread t) break; } - assert(to_do_ > 0); // for safety's sake + assert(to_do_ > 0); // for safety's sake if (print_time_) { @@ -790,14 +834,15 @@ void nest::Scheduler::threaded_update(thread t) } } // while - ready_mutex_.unlock(); // unlock mutex after breaking out of while loop + ready_mutex_.unlock(); // unlock mutex after breaking out of while loop } #else void nest::Scheduler::threaded_update(thread) { - net_.message(SLIInterpreter::M_ERROR, "Scheduler::threaded_update", "Multithreading mode not available"); - throw KernelException(); + net_.message(SLIInterpreter::M_ERROR, "Scheduler::threaded_update", + "Multithreading mode not available"); + throw KernelException(); } #endif @@ -808,7 +853,8 @@ void nest::Scheduler::prepare_nodes() init_moduli_(); - net_.message(SLIInterpreter::M_INFO, "Scheduler::prepare_nodes", "Please wait. Preparing elements."); + net_.message(SLIInterpreter::M_INFO, "Scheduler::prepare_nodes", + "Please wait. Preparing elements."); /* We clear the existing nodes_vec_ and then rebuild it. prepare_node_() below inserts each node into the appropriate @@ -858,28 +904,34 @@ void nest::Scheduler::prepare_nodes() n_nodes_ += nodes_vec_[t].size(); } - std::string msg = String::compose("Simulating %1 nodes.", n_nodes_); + std::string msg, node_str("nodes"); + if (n_nodes_ == 1) node_str = "node"; + msg = String::compose("Simulating %1 local %2.", n_nodes_, node_str); net_.message(SLIInterpreter::M_INFO, "Scheduler::prepare_nodes", msg); } +//!< This function is called only if the thread data structures are properly set up. void nest::Scheduler::finalize_nodes() { + assert(is_prepared_); +#ifdef _OPENMP + net_.message(SLIInterpreter::M_INFO, "Scheduler::finalize_nodes()", " using OpenMP."); +// parallel section begins +#pragma omp parallel + { + index t = omp_get_thread_num(); // which thread am I +#else for (index t = 0; t < n_threads_; ++t) - for(index n = 0; n < net_.size(); ++n) - { - if ( net_.is_local_gid(n) && net_.nodes_[n]!=0 ) - { - if ((*net_.nodes_[n]).num_thread_siblings_() > 0) - (*net_.nodes_[n]).get_thread_sibling_(t)->finalize(); - else - { - Node* node = net_.get_node(n, t); - if (static_cast(node->get_thread()) == t) - node->finalize(); - } - } - } -} + { +#endif + + for (std::vector::iterator i = nodes_vec_[t].begin(); i != nodes_vec_[t].end(); ++i) + (*i)->finalize(); // we assume that the right sibling is stored in nodes_vec_ + + // parallel section ends, wait until all threads are done -> synchronize + } + } + void nest::Scheduler::set_status(DictionaryDatum const &d) { @@ -896,18 +948,18 @@ void nest::Scheduler::set_status(DictionaryDatum const &d) TimeConverter time_converter; double_t time; - if(updateValue(d, "time", time)) + if (updateValue(d, "time", time)) { - if ( time != 0.0 ) + if (time != 0.0) throw BadProperty("The simulation time can only be set to 0.0."); if ( clock_ > Time(Time::step(0)) ) { // reset only if time has passed net_.message(SLIInterpreter::M_WARNING, "Scheduler::set_status", - "Simulation time reset to t=0.0. Resetting the simulation time is not" - "fully supported in NEST at present. Some spikes may be lost, and" - "stimulating devices may behave unexpectedly. PLEASE REVIEW YOUR" + "Simulation time reset to t=0.0. Resetting the simulation time is not " + "fully supported in NEST at present. Some spikes may be lost, and " + "stimulating devices may behave unexpectedly. PLEASE REVIEW YOUR " "SIMULATION OUTPUT CAREFULLY!"); clock_ = Time::step(0); @@ -995,13 +1047,13 @@ void nest::Scheduler::set_status(DictionaryDatum const &d) "Cannot change time representation after nodes have been created. Please call ResetKernel first."); throw KernelException(); } - else if ( net_.get_simulated() ) // someone may have simulated empty network + else if (net_.get_simulated()) // someone may have simulated empty network { net_.message(SLIInterpreter::M_ERROR, "Scheduler::set_status", "Cannot change time representation after the network has been simulated. Please call ResetKernel first."); throw KernelException(); } - else if ( net_.connection_manager_.get_num_connections() != 0 ) + else if (net_.connection_manager_.get_num_connections() != 0) { net_.message(SLIInterpreter::M_ERROR, "Scheduler::set_status", "Cannot change time representation after connections have been created. Please call ResetKernel first."); @@ -1009,7 +1061,7 @@ void nest::Scheduler::set_status(DictionaryDatum const &d) } else if (res_updated && tics_per_ms_updated) // only allow TICS_PER_MS to be changed together with resolution { - if ( resd < 1.0 / tics_per_ms ) + if (resd < 1.0 / tics_per_ms) { net_.message(SLIInterpreter::M_ERROR, "Scheduler::set_status", "Resolution must be greater than or equal to one tic. Value unchanged."); @@ -1017,15 +1069,16 @@ void nest::Scheduler::set_status(DictionaryDatum const &d) } else { - nest::TimeModifier::set_time_representation(tics_per_ms, resd); - clock_.calibrate(); // adjust to new resolution - net_.connection_manager_.calibrate(time_converter); // adjust delays in the connection system to new resolution - net_.message(SLIInterpreter::M_INFO, "Scheduler::set_status", "tics per ms and resolution changed."); + nest::TimeModifier::set_time_representation(tics_per_ms, resd); + clock_.calibrate(); // adjust to new resolution + net_.connection_manager_.calibrate(time_converter); // adjust delays in the connection system to new resolution + net_.message(SLIInterpreter::M_INFO, "Scheduler::set_status", + "tics per ms and resolution changed."); } } else if (res_updated) // only resolution changed { - if ( resd < Time::get_ms_per_tic() ) + if (resd < Time::get_ms_per_tic()) { net_.message(SLIInterpreter::M_ERROR, "Scheduler::set_status", "Resolution must be greater than or equal to one tic. Value unchanged."); @@ -1033,10 +1086,11 @@ void nest::Scheduler::set_status(DictionaryDatum const &d) } else { - Time::set_resolution(resd); - clock_.calibrate(); // adjust to new resolution - net_.connection_manager_.calibrate(time_converter); // adjust delays in the connection system to new resolution - net_.message(SLIInterpreter::M_INFO, "Scheduler::set_status", "Temporal resolution changed."); + Time::set_resolution(resd); + clock_.calibrate(); // adjust to new resolution + net_.connection_manager_.calibrate(time_converter); // adjust delays in the connection system to new resolution + net_.message(SLIInterpreter::M_INFO, "Scheduler::set_status", + "Temporal resolution changed."); } } else @@ -1047,30 +1101,25 @@ void nest::Scheduler::set_status(DictionaryDatum const &d) } } - - bool off_grid_spiking; - bool grid_spiking_updated = updateValue(d, "off_grid_spiking", off_grid_spiking); - if (grid_spiking_updated) - off_grid_spiking_ = off_grid_spiking; + updateValue(d, "off_grid_spiking", off_grid_spiking_); bool comm_allgather; bool commstyle_updated = updateValue(d, "communicate_allgather", comm_allgather); if (commstyle_updated) - Communicator::set_use_Allgather(comm_allgather); + Communicator::set_use_Allgather(comm_allgather); // set RNGs --- MUST come after n_threads_ is updated if (d->known("rngs")) { // this array contains pre-seeded RNGs, so they can be used // directly, no seeding required - ArrayDatum *ad = - dynamic_cast((*d)["rngs"].datum()); - if ( ad == 0 ) + ArrayDatum *ad = dynamic_cast((*d)["rngs"].datum()); + if (ad == 0) throw BadProperty(); // n_threads_ is the new value after a change of the number of // threads - if (ad->size() != (size_t)(Communicator::get_num_virtual_processes())) + if (ad->size() != (size_t) (Communicator::get_num_virtual_processes())) { net_.message(SLIInterpreter::M_ERROR, "Scheduler::set_status", "Number of RNGs must equal number of virtual processes (threads*processes). RNGs unchanged."); @@ -1082,23 +1131,24 @@ void nest::Scheduler::set_status(DictionaryDatum const &d) // set_status, as long as it comes AFTER n_threads_ has been // upated rng_.clear(); - for (index i = 0 ; i < ad->size() ; ++i) - if(is_local_vp(i)) + for (index i = 0; i < ad->size(); ++i) + if (is_local_vp(i)) rng_.push_back(getValue((*ad)[suggest_vp(i)])); } - else if (n_threads_updated && net_.size() == 0) + else if (n_threads_updated && net_.size() == 0) { - net_.message(SLIInterpreter::M_WARNING, "Schedulder::set_status", "Equipping threads with new default RNGs"); + net_.message(SLIInterpreter::M_WARNING, "Scheduler::set_status", + "Equipping threads with new default RNGs"); create_rngs_(); } - if ( d->known("rng_seeds") ) + if (d->known("rng_seeds")) { ArrayDatum *ad = dynamic_cast((*d)["rng_seeds"].datum()); - if ( ad == 0 ) + if (ad == 0) throw BadProperty(); - if (ad->size() != (size_t)(Communicator::get_num_virtual_processes())) + if (ad->size() != (size_t) (Communicator::get_num_virtual_processes())) { net_.message(SLIInterpreter::M_ERROR, "Scheduler::set_status", "Number of seeds must equal number of virtual processes (threads*processes). RNGs unchanged."); @@ -1107,10 +1157,10 @@ void nest::Scheduler::set_status(DictionaryDatum const &d) // check if seeds are unique std::set seedset; - for ( index i = 0 ; i < ad->size() ; ++i ) + for (index i = 0; i < ad->size(); ++i) { - long s = (*ad)[i]; // SLI has no ulong tokens - if ( !seedset.insert(s).second ) + long s = (*ad)[i]; // SLI has no ulong tokens + if (!seedset.insert(s).second) { net_.message(SLIInterpreter::M_WARNING, "Scheduler::set_status", "Seeds are not unique across threads!"); @@ -1119,47 +1169,48 @@ void nest::Scheduler::set_status(DictionaryDatum const &d) } // now apply seeds, resets generators automatically - for ( index i = 0 ; i < ad->size() ; ++i ) + for (index i = 0; i < ad->size(); ++i) { long s = (*ad)[i]; - if(is_local_vp(i)) - rng_[vp_to_thread(suggest_vp(i))]->seed(s); + if (is_local_vp(i)) + rng_[vp_to_thread(suggest_vp(i))]->seed(s); rng_seeds_[i] = s; } } // if rng_seeds - // set GRNG + // set GRNG if (d->known("grng")) { // pre-seeded grng that can be used directly, no seeding required updateValue(d, "grng", grng_); } - else if (n_threads_updated && net_.size() == 0) + else if (n_threads_updated && net_.size() == 0) { - net_.message(SLIInterpreter::M_WARNING, "Schedulder::set_status", "Equipping threads with new default GRNG"); + net_.message(SLIInterpreter::M_WARNING, "Scheduler::set_status", + "Equipping threads with new default GRNG"); create_grng_(); } - if ( d->known("grng_seed") ) + if (d->known("grng_seed")) { - long s = getValue(d, "grng_seed"); + const long gseed = getValue(d, "grng_seed"); // check if grng seed is unique with respect to rng seeds // if grng_seed and rng_seeds given in one SetStatus call std::set seedset; - seedset.insert(s); + seedset.insert(gseed); if (d->known("rng_seeds")) { ArrayDatum *ad_rngseeds = - dynamic_cast((*d)["rng_seeds"].datum()); - if ( ad_rngseeds == 0 ) - throw BadProperty(); - for ( index i = 0 ; i < ad_rngseeds->size() ; ++i ) + dynamic_cast((*d)["rng_seeds"].datum()); + if (ad_rngseeds == 0) + throw BadProperty(); + for (index i = 0; i < ad_rngseeds->size(); ++i) { - s = (*ad_rngseeds)[i]; // SLI has no ulong tokens - if ( !seedset.insert(s).second ) + const long vpseed = (*ad_rngseeds)[i]; // SLI has no ulong tokens + if ( !seedset.insert(vpseed).second ) { net_.message(SLIInterpreter::M_WARNING, "Scheduler::set_status", "Seeds are not unique across threads!"); @@ -1168,19 +1219,19 @@ void nest::Scheduler::set_status(DictionaryDatum const &d) } } // now apply seed, resets generator automatically - grng_seed_ = s; - grng_->seed(s); + grng_seed_ = gseed; + grng_->seed(gseed); } // if grng_seed long rng_bs; - if ( updateValue(d, "rng_buffsize", rng_bs) ) + if (updateValue(d, "rng_buffsize", rng_bs)) { - if ( rng_bs < 1 ) + if (rng_bs < 1) throw BadProperty(); // now apply seeds, resets generators automatically - for ( index i = 0 ; i < rng_.size() ; ++i ) + for (index i = 0; i < rng_.size(); ++i) rng_[i]->set_buffsize(rng_bs); grng_->set_buffsize(rng_bs); } @@ -1234,41 +1285,47 @@ void nest::Scheduler::create_rngs_(const bool ctor_call) // if old generators exist, remove them; since rng_ contains // lockPTRs, we don't have to worry about deletion - if ( rng_.size() > 0 ) + if ( !rng_.empty() ) { - if ( !ctor_call ) - net_.message(SLIInterpreter::M_INFO, "Scheduler::create_rngs_", "Deleting existing random number generators"); + if (!ctor_call) + net_.message(SLIInterpreter::M_INFO, "Scheduler::create_rngs_", + "Deleting existing random number generators"); rng_.clear(); } // create new rngs - if ( !ctor_call ) + if (!ctor_call) net_.message(SLIInterpreter::M_INFO, "Scheduler::create_rngs_", "Creating default RNGs"); rng_seeds_.resize(Communicator::get_num_virtual_processes()); - for ( index i = 0; i < static_cast(Communicator::get_num_virtual_processes()); ++i ) + for (index i = 0; i < static_cast(Communicator::get_num_virtual_processes()); ++i ) { unsigned long s = i + 1; - if(is_local_vp(i)) + if (is_local_vp(i)) { /* - We have to ensure that each thread is provided with a different - stream of random numbers. The seeding method for Knuth's LFG - generator guarantees that different seeds yield non-overlapping - random number sequences. - - We therefore have to seed with known numbers: using random - seeds here would run the risk of using the same seed twice. - For simplicity, we use 1 .. n_vps. - */ + We have to ensure that each thread is provided with a different + stream of random numbers. The seeding method for Knuth's LFG + generator guarantees that different seeds yield non-overlapping + random number sequences. + + We therefore have to seed with known numbers: using random + seeds here would run the risk of using the same seed twice. + For simplicity, we use 1 .. n_vps. + */ +#ifdef HAVE_GSL + librandom::RngPtr rng(new librandom::GslRandomGen(gsl_rng_knuthran2002, s)); +#else librandom::RngPtr rng = librandom::RandomGen::create_knuthlfg_rng(s); +#endif - if ( !rng ) + if (!rng) { - if ( !ctor_call ) - net_.message(SLIInterpreter::M_ERROR, "Scheduler::create_rngs_", "Error initializing knuthlfg"); + if (!ctor_call) + net_.message(SLIInterpreter::M_ERROR, "Scheduler::create_rngs_", + "Error initializing knuthlfg"); else std::cerr << "\nScheduler::create_rngs_\n" << "Error initializing knuthlfg" << std::endl; @@ -1286,31 +1343,33 @@ void nest::Scheduler::create_grng_(const bool ctor_call) { // create new grng - if ( !ctor_call ) - net_.message(SLIInterpreter::M_INFO, "Scheduler::create_grng_", "Creating new default global RNG"); + if (!ctor_call) + net_.message(SLIInterpreter::M_INFO, "Scheduler::create_grng_", + "Creating new default global RNG"); // create default RNG with default seed +#ifdef HAVE_GSL + grng_ = librandom::RngPtr(new librandom::GslRandomGen(gsl_rng_knuthran2002, librandom::RandomGen::DefaultSeed)); +#else grng_ = librandom::RandomGen::create_knuthlfg_rng(librandom::RandomGen::DefaultSeed); +#endif if ( !grng_ ) - { - if ( !ctor_call ) - net_.message(SLIInterpreter::M_ERROR, "Scheduler::create_grng_", - "Error initializing knuthlfg"); - else - std::cerr << "\nScheduler::create_grng_\n" - << "Error initializing knuthlfg" - << std::endl; + { + if ( !ctor_call ) + net_.message(SLIInterpreter::M_ERROR, "Scheduler::create_grng_", "Error initializing knuthlfg"); + else + std::cerr << "\nScheduler::create_grng_\n" << "Error initializing knuthlfg" << std::endl; - throw KernelException(); - } + throw KernelException(); + } /* - The seed for the global rng should be different from the seeds - of the local rngs_ for each thread seeded with 1,..., n_vps. - */ - long s = Communicator::get_num_virtual_processes() + 1; - grng_seed_ = s; + The seed for the global rng should be different from the seeds + of the local rngs_ for each thread seeded with 1,..., n_vps. + */ + long s = 0; + grng_seed_ = s; grng_->seed(s); } @@ -1330,23 +1389,18 @@ void nest::Scheduler::collocate_buffers_() std::vector > >::iterator it; std::vector >::iterator jt; - for (it = offgrid_spike_register_.begin(); it != offgrid_spike_register_.end(); ++it) + for (it = offgrid_spike_register_.begin(); + it != offgrid_spike_register_.end(); ++it) for (jt = it->begin(); jt != it->end(); ++jt) num_offgrid_spikes += jt->size(); num_spikes = num_grid_spikes + num_offgrid_spikes; - if (!off_grid_spiking_) //on grid spiking + if (!off_grid_spiking_) // on grid spiking { - // make sure buffers are correctly sized and empty - std::vector tmp(global_grid_spikes_.size(), 0); - global_grid_spikes_.swap(tmp); - + // make sure buffers are correctly sized if (global_grid_spikes_.size() != static_cast(Communicator::get_recv_buffer_size())) global_grid_spikes_.resize(Communicator::get_recv_buffer_size(), 0); - std::vector tmp2(local_grid_spikes_.size(), 0); - local_grid_spikes_.swap(tmp2); - if (num_spikes + (n_threads_ * min_delay_) > static_cast(Communicator::get_send_buffer_size())) local_grid_spikes_.resize((num_spikes + (min_delay_ * n_threads_)),0); else if (local_grid_spikes_.size() < static_cast(Communicator::get_send_buffer_size())) @@ -1373,7 +1427,7 @@ void nest::Scheduler::collocate_buffers_() for (j = i->begin(); j != i->end(); ++j) { pos = std::copy(j->begin(), j->end(), pos); - for (n = jt->begin() ; n != jt->end() ; ++n ) + for (n = jt->begin(); n != jt->end(); ++n) { *pos = n->get_gid(); ++pos; @@ -1386,7 +1440,7 @@ void nest::Scheduler::collocate_buffers_() } for (it = offgrid_spike_register_.begin(); it != offgrid_spike_register_.end(); ++it) for (jt = it->begin(); jt != it->end(); ++jt) - jt->clear(); + jt->clear(); } // remove old spikes from the spike_register_ @@ -1394,18 +1448,12 @@ void nest::Scheduler::collocate_buffers_() for (j = i->begin(); j != i->end(); ++j) j->clear(); } - else //off_grid_spiking + else // off_grid_spiking { - // make sure buffers are correctly sized and empty - std::vector tmp(global_offgrid_spikes_.size(), OffGridSpike(0,0.0)); - global_offgrid_spikes_.swap(tmp); - + // make sure buffers are correctly sized if (global_offgrid_spikes_.size() != static_cast(Communicator::get_recv_buffer_size())) global_offgrid_spikes_.resize(Communicator::get_recv_buffer_size(), OffGridSpike(0,0.0)); - std::vector tmp2(local_offgrid_spikes_.size(), OffGridSpike(0,0.0)); - local_offgrid_spikes_.swap(tmp2); - if (num_spikes + (n_threads_ * min_delay_) > static_cast(Communicator::get_send_buffer_size())) local_offgrid_spikes_.resize((num_spikes + (min_delay_ * n_threads_)), OffGridSpike(0,0.0)); else if (local_offgrid_spikes_.size() < static_cast(Communicator::get_send_buffer_size())) @@ -1431,7 +1479,7 @@ void nest::Scheduler::collocate_buffers_() for (jt = it->begin(); jt != it->end(); ++jt) { pos = std::copy(jt->begin(), jt->end(), pos); - for (n = j->begin() ; n != j->end() ; ++n ) + for (n = j->begin(); n != j->end(); ++n) { *pos = OffGridSpike(*n,0); ++pos; @@ -1457,7 +1505,7 @@ void nest::Scheduler::collocate_buffers_() void nest::Scheduler::deliver_events_(thread t) { // deliver only at beginning of time slice - if ( from_step_ > 0 ) + if (from_step_ > 0) return; size_t n_markers = 0; @@ -1467,17 +1515,24 @@ void nest::Scheduler::deliver_events_(thread t) if (!off_grid_spiking_) //on_grid_spiking { + // prepare Time objects for every possible time stamp within min_delay_ + std::vector