Skip to content

Commit a2e2287

Browse files
authored
Merge pull request #2948 from heplesser/fix-examples
Fix bug in reconstruction of connection data structures after disconnect and fix small problems with examples
2 parents 4d8d3bf + dbcc1cd commit a2e2287

9 files changed

+104
-52
lines changed

examples/run_examples.sh

+3-1
Original file line numberDiff line numberDiff line change
@@ -93,11 +93,13 @@ for i in $EXAMPLES; do
9393
echo " output_dir: '$output_dir'" >>"$metafile"
9494
echo " log: '$logfile'" >>"$metafile"
9595

96-
export NEST_DATA_PATH="" # $output_dir"
96+
export NEST_DATA_PATH="$output_dir"
9797
touch .start_example
9898
sleep 1
9999
set +e
100+
# The following line will not work on macOS. There, `brew install gnu-time` and use the commented-out line below.
100101
/usr/bin/time -f "$time_format" --quiet sh -c "'$runner' '$example' >'$logfile' 2>&1" |& tee -a "$metafile"
102+
# /usr/local/bin/gtime -f "$time_format" --quiet sh -c "'$runner' '$example' >'$logfile' 2>&1" | tee -a "$metafile" 2>&1
101103
ret=$?
102104
set -e
103105

nestkernel/connection_manager.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -1583,6 +1583,10 @@ nest::ConnectionManager::remove_disabled_connections( const size_t tid )
15831583
{
15841584
continue;
15851585
}
1586+
1587+
// Source table and connectors are sorted synchronously. All invalid connections have
1588+
// been sorted to end of source_table_. We find them there, then remove corresponding
1589+
// elements from connectors.
15861590
const size_t first_disabled_index = source_table_.remove_disabled_sources( tid, syn_id );
15871591

15881592
if ( first_disabled_index != invalid_index )

nestkernel/connector_base.h

+1
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,7 @@ class Connector : public ConnectorBase
392392

393393
while ( true )
394394
{
395+
assert( lcid + lcid_offset < C_.size() );
395396
ConnectionT& conn = C_[ lcid + lcid_offset ];
396397
const bool is_disabled = conn.is_disabled();
397398
const bool source_has_more_targets = conn.source_has_more_targets();

nestkernel/simulation_manager.cpp

+36-34
Original file line numberDiff line numberDiff line change
@@ -811,40 +811,6 @@ nest::SimulationManager::update_()
811811
gettimeofday( &t_slice_begin_, nullptr );
812812
}
813813

814-
if ( kernel().sp_manager.is_structural_plasticity_enabled()
815-
and ( std::fmod( Time( Time::step( clock_.get_steps() + from_step_ ) ).get_ms(),
816-
kernel().sp_manager.get_structural_plasticity_update_interval() )
817-
== 0 ) )
818-
{
819-
for ( SparseNodeArray::const_iterator i = kernel().node_manager.get_local_nodes( tid ).begin();
820-
i != kernel().node_manager.get_local_nodes( tid ).end();
821-
++i )
822-
{
823-
Node* node = i->get_node();
824-
node->update_synaptic_elements( Time( Time::step( clock_.get_steps() + from_step_ ) ).get_ms() );
825-
}
826-
#pragma omp barrier
827-
#pragma omp single
828-
{
829-
kernel().sp_manager.update_structural_plasticity();
830-
}
831-
// Remove 10% of the vacant elements
832-
for ( SparseNodeArray::const_iterator i = kernel().node_manager.get_local_nodes( tid ).begin();
833-
i != kernel().node_manager.get_local_nodes( tid ).end();
834-
++i )
835-
{
836-
Node* node = i->get_node();
837-
node->decay_synaptic_elements_vacant();
838-
}
839-
840-
// after structural plasticity has created and deleted
841-
// connections, update the connection infrastructure; implies
842-
// complete removal of presynaptic part and reconstruction
843-
// from postsynaptic data
844-
update_connection_infrastructure( tid );
845-
846-
} // of structural plasticity
847-
848814
// Do not deliver events at beginning of first slice, nothing can be there yet
849815
// and invalid markers have not been properly set in send buffers.
850816
if ( slice_ > 0 and from_step_ == 0 )
@@ -989,6 +955,42 @@ nest::SimulationManager::update_()
989955
} // of if(wfr_is_used)
990956
// end of preliminary update
991957

958+
if ( kernel().sp_manager.is_structural_plasticity_enabled()
959+
and ( std::fmod( Time( Time::step( clock_.get_steps() + from_step_ ) ).get_ms(),
960+
kernel().sp_manager.get_structural_plasticity_update_interval() )
961+
== 0 ) )
962+
{
963+
#pragma omp barrier
964+
for ( SparseNodeArray::const_iterator i = kernel().node_manager.get_local_nodes( tid ).begin();
965+
i != kernel().node_manager.get_local_nodes( tid ).end();
966+
++i )
967+
{
968+
Node* node = i->get_node();
969+
node->update_synaptic_elements( Time( Time::step( clock_.get_steps() + from_step_ ) ).get_ms() );
970+
}
971+
#pragma omp barrier
972+
#pragma omp single
973+
{
974+
kernel().sp_manager.update_structural_plasticity();
975+
}
976+
// Remove 10% of the vacant elements
977+
for ( SparseNodeArray::const_iterator i = kernel().node_manager.get_local_nodes( tid ).begin();
978+
i != kernel().node_manager.get_local_nodes( tid ).end();
979+
++i )
980+
{
981+
Node* node = i->get_node();
982+
node->decay_synaptic_elements_vacant();
983+
}
984+
985+
// after structural plasticity has created and deleted
986+
// connections, update the connection infrastructure; implies
987+
// complete removal of presynaptic part and reconstruction
988+
// from postsynaptic data
989+
update_connection_infrastructure( tid );
990+
991+
} // of structural plasticity
992+
993+
992994
#ifdef TIMER_DETAILED
993995
#pragma omp barrier
994996
if ( tid == 0 )

nestkernel/source_table.cpp

+12-9
Original file line numberDiff line numberDiff line change
@@ -166,14 +166,14 @@ nest::SourceTable::remove_disabled_sources( const size_t tid, const synindex syn
166166
{
167167
if ( sources_[ tid ].size() <= syn_id )
168168
{
169-
return invalid_index;
169+
return invalid_index; // no source table entry for this synapse model
170170
}
171171

172172
BlockVector< Source >& mysources = sources_[ tid ][ syn_id ];
173173
const size_t max_size = mysources.size();
174174
if ( max_size == 0 )
175175
{
176-
return invalid_index;
176+
return invalid_index; // no connections for this synapse model
177177
}
178178

179179
// lcid needs to be signed, to allow lcid >= 0 check in while loop
@@ -184,15 +184,14 @@ nest::SourceTable::remove_disabled_sources( const size_t tid, const synindex syn
184184
{
185185
--lcid;
186186
}
187-
++lcid; // lcid marks first disabled source, but the while loop only
188-
// exits if lcid points at a not disabled element, hence we
189-
// need to increase it by one again
190-
mysources.erase( mysources.begin() + lcid, mysources.end() );
191-
if ( static_cast< size_t >( lcid ) == max_size )
187+
const size_t first_invalid_lcid = static_cast< size_t >( lcid + 1 ); // loop stopped on first valid entry or -1
188+
if ( first_invalid_lcid == max_size )
192189
{
193-
return invalid_index;
190+
return invalid_index; // all lcids are valid, nothing to remove
194191
}
195-
return static_cast< size_t >( lcid );
192+
193+
mysources.erase( mysources.begin() + first_invalid_lcid, mysources.end() );
194+
return first_invalid_lcid;
196195
}
197196

198197
void
@@ -458,6 +457,10 @@ nest::SourceTable::collect_compressible_sources( const size_t tid )
458457
kernel().connection_manager.set_source_has_more_targets( tid, syn_id, lcid - 1, true );
459458
++lcid;
460459
}
460+
// Mark last connection in sequence as not having successor. This is essential if connections are
461+
// delete, e.g., by structural plasticity, because we do not globally reset the more_targets flag.
462+
assert( lcid - 1 < syn_sources.size() );
463+
kernel().connection_manager.set_source_has_more_targets( tid, syn_id, lcid - 1, false );
461464
}
462465
}
463466
}

pynest/examples/evaluate_quantal_stp_synapse.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@
8484

8585
# We define the number of trials as well as the number of release sites.
8686

87-
n_sites = 10.0 # number of synaptic release sites
87+
n_sites = 10 # number of synaptic release sites
8888
n_trials = 500 # number of measurement trials
8989

9090
# The pre-synaptic neuron is driven by an injected current for a part of each

pynest/examples/pong/README.rst

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ the classic game of Pong.
55

66
Requirements
77
------------
8-
- NEST 3.3
8+
- NEST 3.3 or later
99
- NumPy
1010
- Matplotlib
1111

@@ -19,4 +19,4 @@ based on the ``stdp_dopamine_synapse`` and temporal difference learning
1919
is implemented, see ``networks.py`` for details.
2020

2121
The learning progress and resulting game can be visualized with the
22-
``generate_gif.py`` script.
22+
``generate_gif.py`` script.

pynest/examples/store_restore_network.py

+1-5
Original file line numberDiff line numberDiff line change
@@ -304,8 +304,6 @@ def add_to_plot(self, net, n_max=100, t_min=0, t_max=1000, lbl=""):
304304

305305

306306
if __name__ == "__main__":
307-
plt.ion()
308-
309307
T_sim = 1000
310308

311309
dplot = DemoPlot()
@@ -370,6 +368,4 @@ def add_to_plot(self, net, n_max=100, t_min=0, t_max=1000, lbl=""):
370368
nest.Simulate(T_sim)
371369
dplot.add_to_plot(ein2, lbl="Reloaded simulation (different seed)")
372370

373-
dplot.fig.savefig("store_restore_network.png")
374-
375-
input("Press ENTER to close figure!")
371+
plt.show()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# -*- coding: utf-8 -*-
2+
#
3+
# test_spike_transmission_after_disconnect.py
4+
#
5+
# This file is part of NEST.
6+
#
7+
# Copyright (C) 2004 The NEST Initiative
8+
#
9+
# NEST is free software: you can redistribute it and/or modify
10+
# it under the terms of the GNU General Public License as published by
11+
# the Free Software Foundation, either version 2 of the License, or
12+
# (at your option) any later version.
13+
#
14+
# NEST is distributed in the hope that it will be useful,
15+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+
# GNU General Public License for more details.
18+
#
19+
# You should have received a copy of the GNU General Public License
20+
# along with NEST. If not, see <http://www.gnu.org/licenses/>.
21+
22+
import nest
23+
24+
25+
def test_spike_transmission_after_disconnect():
26+
"""
27+
Confirm that spikes can be transmitted after connections have been removed.
28+
"""
29+
30+
n = nest.Create("parrot_neuron", 10)
31+
nest.Connect(n, n)
32+
33+
# Delete 1/3 of connections
34+
c = nest.GetConnections()
35+
c[::3].disconnect()
36+
37+
# Add spike generator to drive
38+
g = nest.Create("spike_generator", params={"spike_times": [1]})
39+
nest.Connect(g, n)
40+
41+
# Simulate long enough for spikes to be delivered, but not too long
42+
# since we otherwise will be buried by exponential growth in number
43+
# of spikes.
44+
nest.Simulate(3)

0 commit comments

Comments
 (0)