-
Notifications
You must be signed in to change notification settings - Fork 389
Fix issue: #3532: Disconnect issue with CompressedSpikes:ON/Off #3536
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
|
@med-ayssar Thanks for your detective work and the PR! I will look at it in detail asap. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@med-ayssar Thanks for the PR! I am not entirely sure I follow the logic around nth_equal(), see comments below.
I also wonder if, for the uncompressed case, we should not take a different approach. In that case, I believe, we simply need to run through all connections of a given synapse type linearly and disconnect the first one for which source and target match, and which has not yet been disconnected. I guess that means parallel iteration through source and target tables. The split into find_first_source() and find_first_target() does not make sense in that case.
We also need some tests, including tests where there are multiple connections between the same source-target pair and we delete one at a time.
|
@heplesser: Is it possible to setup a meeting to discuss this? Any time after 17:30 should work for me. |
|
@heplesser :You’re a bit fast. I’m just using this time to adjust things while waiting for other processes to compile at work :D, but final version at night :D. |
|
@heplesser: By the way, when deleting a connection, we mark the corresponding entry in the source table with [std::lower_bound](https://en.cppreference.com/w/cpp/algorithm/lower_bound.html#:~:text=exists.-,If%20the%20elements,%2C%20the%20behavior%20is%20undefined.,-(until%20C%2B%2B20): |
|
@med-ayssar Good catch that you noticed the undefined behavior of |
|
I found another issue that occurs when compressed spikes is turned off. It should be fixed now, and once the CI is green, I’ll update the description with an explanation of the problem. |
|
@heplesser please take a look again.
|
|
@heplesser (CC @JanVogelsang ): It seems that in Am I getting it correctly? |
Hm good question, it's not 100% . But couldn't we just use a custom Comp-Operator here which handles disabled node ids? Something like: []( const Source& source, const size_t node_id ){
return source.get_node_id() == DISABLED_NODE_ID or source.get_node_id() < node_id;
}Or what am I missing here? Maybe I didn't understand our problem. |
|
|
@med-ayssar Thanks for working this through so carefully! As far as I understand the C++ documentation, there is no difference concerning undefined behavior for I did not quite get your point that disconnecting breaks the ordering of the source table. |
|
In my last commits, I separated the search for the connection in the When we disconnect, we disable the wrong source entry, but now it should work If you test with the current master, and delete the edges as the given order of The reason is that a previous deletion of a connection disabled the wrong source-entry. |
|
Ah yes, true. But HEP's suggestion would fix it (disabled flag). |
To Summarize:
|
|
[Off-topic]: In NEST, disconnecting means marking certain objects (i.e, It happens here: check the while-loop, and you will see why nothing is removed in some cases, despite they are marked for removal (disabled).
size_t
nest::SourceTable::remove_disabled_sources( const size_t tid, const synindex syn_id )
{
if ( sources_[ tid ].size() <= syn_id )
{
return invalid_index; // no source table entry for this synapse model
}
BlockVector< Source >& mysources = sources_[ tid ][ syn_id ];
const size_t max_size = mysources.size();
if ( max_size == 0 )
{
return invalid_index; // no connections for this synapse model
}
// lcid needs to be signed, to allow lcid >= 0 check in while loop
// to fail; afterwards we can be certain that it is non-negative and
// we can static_cast it to index
long lcid = max_size - 1;
while ( lcid >= 0 and mysources[ lcid ].is_disabled() )
{
--lcid;
}
const size_t first_invalid_lcid = static_cast< size_t >( lcid + 1 ); // loop stopped on first valid entry or -1
if ( first_invalid_lcid == max_size )
{
return invalid_index; // all lcids are valid, nothing to remove
}
mysources.erase( mysources.begin() + first_invalid_lcid, mysources.end() );
return first_invalid_lcid;
}
|
|
@med-ayssar In isolation, you are right that |
|
Fair enough, but remember, the source table is not always sorted ( compressed spikes are off ). Otherwise the PR is ready for reviewing. |
| @@ -0,0 +1,83 @@ | |||
| # -*- coding: utf-8 -*- | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this is a regression test, please rename it to test_regression_issue-3532.py.
Fix for #3532
The main issue occurs when CompressedSpikes is disabled — the wrong connection gets deleted. The following image illustrates the problem."
Issues:
With
compressed-spikesoff,std::lower_boundwas being applied onunsortedvector.With
compressed-spikesoff, and regardless of (1), disconnecting a connection was not implemented correctly, because the query on thesnode_idandtnode_iddelivers a wronglcid.While testing, I discovered that disconnecting a connection, it changes the entry in the
sourceTable, and when working with a sortedsourceTable(compressed-spikes=true), we might get anundefined behaviour