NEST main@caf0ae8
 
Loading...
Searching...
No Matches
connection_creator_impl.h
Go to the documentation of this file.
1/*
2 * connection_creator_impl.h
3 *
4 * This file is part of NEST.
5 *
6 * Copyright (C) 2004 The NEST Initiative
7 *
8 * NEST is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * NEST is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with NEST. If not, see <http://www.gnu.org/licenses/>.
20 *
21 */
22
23#ifndef CONNECTION_CREATOR_IMPL_H
24#define CONNECTION_CREATOR_IMPL_H
25
26#include "connection_creator.h"
27
28// C++ includes:
29#include <vector>
30
31// Includes from nestkernel:
32#include "kernel_manager.h"
33
34namespace nest
35{
36template < int D >
37void
39 NodeCollectionPTR source_nc,
40 Layer< D >& target,
41 NodeCollectionPTR target_nc )
42{
43 switch ( type_ )
44 {
46
47 pairwise_bernoulli_on_source_( source, source_nc, target, target_nc );
48 break;
49
50 case Fixed_indegree:
51
52 fixed_indegree_( source, source_nc, target, target_nc );
53 break;
54
55 case Fixed_outdegree:
56
57 fixed_outdegree_( source, source_nc, target, target_nc );
58 break;
59
61
62 pairwise_bernoulli_on_target_( source, source_nc, target, target_nc );
63 break;
64
66
67 pairwise_poisson_( source, source_nc, target, target_nc );
68 break;
69
70 default:
71 throw BadProperty( "Unknown connection type." );
72 }
73}
74
75template < typename Iterator, int D >
76void
78 Iterator to,
79 Node* tgt_ptr,
80 const Position< D >& tgt_pos,
81 size_t tgt_thread,
82 const Layer< D >& source )
83{
84 RngPtr rng = get_vp_specific_rng( tgt_thread );
85
86 // We create a source pos vector here that can be updated with the
87 // source position. This is done to avoid creating and destroying
88 // unnecessarily many vectors.
89 std::vector< double > source_pos( D );
90 const std::vector< double > target_pos = tgt_pos.get_vector();
91
92 for ( Iterator iter = from; iter != to; ++iter )
93 {
94 if ( not allow_autapses_ and ( iter->second == tgt_ptr->get_node_id() ) )
95 {
96 continue;
97 }
98 iter->first.get_vector( source_pos );
99
100 if ( not kernel_ or rng->drand() < kernel_->value( rng, source_pos, target_pos, source, tgt_ptr ) )
101 {
102 for ( size_t indx = 0; indx < synapse_model_.size(); ++indx )
103 {
104 kernel().connection_manager.connect( iter->second,
105 tgt_ptr,
106 tgt_thread,
107 synapse_model_[ indx ],
108 param_dicts_[ indx ][ tgt_thread ],
109 delay_[ indx ]->value( rng, source_pos, target_pos, source, tgt_ptr ),
110 weight_[ indx ]->value( rng, source_pos, target_pos, source, tgt_ptr ) );
111 }
112 }
113 }
114}
115
116template < typename Iterator, int D >
117void
119 Iterator to,
120 Node* tgt_ptr,
121 const Position< D >& tgt_pos,
122 size_t tgt_thread,
123 const Layer< D >& source )
124{
125 RngPtr rng = get_vp_specific_rng( tgt_thread );
126
127 // We create a source pos vector here that can be updated with the
128 // source position. This is done to avoid creating and destroying
129 // unnecessarily many vectors.
130 std::vector< double > source_pos( D );
131 const std::vector< double > target_pos = tgt_pos.get_vector();
132 poisson_distribution poi_dist;
133
134 for ( Iterator iter = from; iter != to; ++iter )
135 {
136 if ( not allow_autapses_ and ( iter->second == tgt_ptr->get_node_id() ) )
137 {
138 continue;
139 }
140 iter->first.get_vector( source_pos );
141
142 // Sample number of connections that are to be established
143 poisson_distribution::param_type param( kernel_->value( rng, source_pos, target_pos, source, tgt_ptr ) );
144 const unsigned long num_conns = poi_dist( rng, param );
145 for ( unsigned long conn_counter = 0; conn_counter < num_conns; ++conn_counter )
146 {
147 for ( size_t indx = 0; indx < synapse_model_.size(); ++indx )
148 {
149 kernel().connection_manager.connect( iter->second,
150 tgt_ptr,
151 tgt_thread,
152 synapse_model_[ indx ],
153 param_dicts_[ indx ][ tgt_thread ],
154 delay_[ indx ]->value( rng, source_pos, target_pos, source, tgt_ptr ),
155 weight_[ indx ]->value( rng, source_pos, target_pos, source, tgt_ptr ) );
156 }
157 }
158 }
159}
160
161template < int D >
163 : masked_layer_( 0 )
164 , positions_( 0 )
165{
166}
167
168template < int D >
170{
171 if ( masked_layer_ )
172 {
173 delete masked_layer_;
174 }
175}
176
177template < int D >
178void
180{
181 assert( masked_layer_ == 0 );
182 assert( positions_ == 0 );
183 assert( ml != 0 );
184 masked_layer_ = ml;
185}
186
187template < int D >
188void
189ConnectionCreator::PoolWrapper_< D >::define( std::vector< std::pair< Position< D >, size_t > >* pos )
190{
191 assert( masked_layer_ == 0 );
192 assert( positions_ == 0 );
193 assert( pos != 0 );
194 positions_ = pos;
195}
196
197template < int D >
200{
201 return masked_layer_->begin( pos );
202}
203
204template < int D >
207{
208 return masked_layer_->end();
209}
210
211template < int D >
212typename std::vector< std::pair< Position< D >, size_t > >::iterator
214{
215 return positions_->begin();
216}
217
218template < int D >
219typename std::vector< std::pair< Position< D >, size_t > >::iterator
221{
222 return positions_->end();
223}
224
225
226template < int D >
227void
229 NodeCollectionPTR source_nc,
230 Layer< D >& target,
231 NodeCollectionPTR target_nc )
232{
233 // Connect using pairwise Bernoulli drawing source nodes (target driven)
234 // For each local target node:
235 // 1. Apply Mask to source layer
236 // 2. For each source node: Compute probability, draw random number, make
237 // connection conditionally
238
239 // retrieve global positions, either for masked or unmasked pool
241 if ( mask_.get() ) // MaskedLayer will be freed by PoolWrapper d'tor
242 {
243 pool.define( new MaskedLayer< D >( source, mask_, allow_oversized_, source_nc ) );
244 }
245 else
246 {
247 pool.define( source.get_global_positions_vector( source_nc ) );
248 }
249
250 std::vector< std::exception_ptr > exceptions_raised_( kernel().vp_manager.get_num_threads() );
251
252#pragma omp parallel
253 {
254 const int tid = kernel().vp_manager.get_thread_id();
255 try
256 {
257 NodeCollection::const_iterator target_begin = target_nc->begin();
258 NodeCollection::const_iterator target_end = target_nc->end();
259
260 for ( NodeCollection::const_iterator tgt_it = target_begin; tgt_it < target_end; ++tgt_it )
261 {
262 Node* const tgt = kernel().node_manager.get_node_or_proxy( ( *tgt_it ).node_id, tid );
263
264 if ( not tgt->is_proxy() )
265 {
266 const Position< D > target_pos = target.get_position( ( *tgt_it ).nc_index );
267
268 if ( mask_.get() )
269 {
270 connect_to_target_( pool.masked_begin( target_pos ), pool.masked_end(), tgt, target_pos, tid, source );
271 }
272 else
273 {
274 connect_to_target_( pool.begin(), pool.end(), tgt, target_pos, tid, source );
275 }
276 }
277 } // for target_begin
278 }
279 catch ( ... )
280 {
281 // Capture the current exception object and create an std::exception_ptr
282 exceptions_raised_.at( tid ) = std::current_exception();
283 }
284 } // omp parallel
285
286 // check if any exceptions have been raised
287 for ( auto eptr : exceptions_raised_ )
288 {
289 if ( eptr )
290 {
291 std::rethrow_exception( eptr );
292 }
293 }
294}
295
296
297template < int D >
298void
300 NodeCollectionPTR source_nc,
301 Layer< D >& target,
302 NodeCollectionPTR target_nc )
303{
304 // Connecting using pairwise Bernoulli drawing target nodes (source driven)
305 // It is actually implemented as pairwise Bernoulli on source nodes,
306 // but with displacements computed in the target layer. The Mask has been
307 // reversed so that it can be applied to the source instead of the target.
308 // For each local target node:
309 // 1. Apply (Converse)Mask to source layer
310 // 2. For each source node: Compute probability, draw random number, make
311 // connection conditionally
312
314 if ( mask_.get() ) // MaskedLayer will be freed by PoolWrapper d'tor
315 {
316 // By supplying the target layer to the MaskedLayer constructor, the
317 // mask is mirrored so it may be applied to the source layer instead
318 pool.define( new MaskedLayer< D >( source, mask_, allow_oversized_, target, source_nc ) );
319 }
320 else
321 {
322 pool.define( source.get_global_positions_vector( source_nc ) );
323 }
324
325 std::vector< std::exception_ptr > exceptions_raised_( kernel().vp_manager.get_num_threads() );
326
327 // We only need to check the first in the NodeCollection
328 Node* const first_in_tgt = kernel().node_manager.get_node_or_proxy( target_nc->operator[]( 0 ) );
329 if ( not first_in_tgt->has_proxies() )
330 {
331 throw IllegalConnection( "Spatial Connect with pairwise_bernoulli to devices is not possible." );
332 }
333
334#pragma omp parallel
335 {
336 const int tid = kernel().vp_manager.get_thread_id();
337 try
338 {
339 NodeCollection::const_iterator target_begin = target_nc->thread_local_begin();
340 NodeCollection::const_iterator target_end = target_nc->end();
341
342 for ( NodeCollection::const_iterator tgt_it = target_begin; tgt_it < target_end; ++tgt_it )
343 {
344 Node* const tgt = kernel().node_manager.get_node_or_proxy( ( *tgt_it ).node_id, tid );
345
346 assert( not tgt->is_proxy() );
347
348 const Position< D > target_pos = target.get_position( ( *tgt_it ).nc_index );
349
350 if ( mask_.get() )
351 {
352 // We do the same as in the target driven case, except that we calculate displacements in the target layer.
353 // We therefore send in target as last parameter.
354 connect_to_target_( pool.masked_begin( target_pos ), pool.masked_end(), tgt, target_pos, tid, target );
355 }
356 else
357 {
358 // We do the same as in the target driven case, except that we calculate displacements in the target layer.
359 // We therefore send in target as last parameter.
360 connect_to_target_( pool.begin(), pool.end(), tgt, target_pos, tid, target );
361 }
362
363 } // end for
364 }
365 catch ( ... )
366 {
367 // Capture the current exception object and create an std::exception_ptr
368 exceptions_raised_.at( tid ) = std::current_exception();
369 }
370 } // omp parallel
371
372 // check if any exceptions have been raised
373 for ( auto eptr : exceptions_raised_ )
374 {
375 if ( eptr )
376 {
377 std::rethrow_exception( eptr );
378 }
379 }
380}
381
382
383template < int D >
384void
386 NodeCollectionPTR source_nc,
387 Layer< D >& target,
388 NodeCollectionPTR target_nc )
389{
390 // Connect using pairwise Poisson drawing source nodes (target driven)
391 // For each local target node:
392 // 1. Apply Mask to source layer
393 // 2. For each source node: Compute probability, draw random number, make
394 // connection conditionally
395
396 // retrieve global positions, either for masked or unmasked pool
398 if ( mask_.get() ) // MaskedLayer will be freed by PoolWrapper d'tor
399 {
400 pool.define( new MaskedLayer< D >( source, mask_, allow_oversized_, source_nc ) );
401 }
402 else
403 {
404 pool.define( source.get_global_positions_vector( source_nc ) );
405 }
406
407 std::vector< std::exception_ptr > exceptions_raised_( kernel().vp_manager.get_num_threads() );
408
409#pragma omp parallel
410 {
411 const int thread_id = kernel().vp_manager.get_thread_id();
412 try
413 {
414 NodeCollection::const_iterator target_begin = target_nc->begin();
415 NodeCollection::const_iterator target_end = target_nc->end();
416
417 for ( NodeCollection::const_iterator tgt_it = target_begin; tgt_it < target_end; ++tgt_it )
418 {
419 Node* const tgt = kernel().node_manager.get_node_or_proxy( ( *tgt_it ).node_id, thread_id );
420
421 if ( not tgt->is_proxy() )
422 {
423 const Position< D > target_pos = target.get_position( ( *tgt_it ).nc_index );
424
425 if ( mask_.get() )
426 {
428 pool.masked_begin( target_pos ), pool.masked_end(), tgt, target_pos, thread_id, source );
429 }
430 else
431 {
432 connect_to_target_poisson_( pool.begin(), pool.end(), tgt, target_pos, thread_id, source );
433 }
434 }
435 } // for target_begin
436 }
437 catch ( ... )
438 {
439 exceptions_raised_.at( thread_id ) = std::current_exception();
440 }
441 } // omp parallel
442
443 // check if any exceptions have been raised
444 for ( auto eptr : exceptions_raised_ )
445 {
446 if ( eptr )
447 {
448 std::rethrow_exception( eptr );
449 }
450 }
451}
452
453
454template < int D >
455void
457 NodeCollectionPTR source_nc,
458 Layer< D >& target,
459 NodeCollectionPTR target_nc )
460{
461 // fixed_indegree connections (fixed fan in)
462 //
463 // For each local target node:
464 // 1. Apply Mask to source layer
465 // 2. Compute connection probability for each source position
466 // 3. Draw source nodes and make connections
467
468 // We only need to check the first in the NodeCollection
469 Node* const first_in_tgt = kernel().node_manager.get_node_or_proxy( target_nc->operator[]( 0 ) );
470 if ( not first_in_tgt->has_proxies() )
471 {
472 throw IllegalConnection( "Spatial Connect with fixed_indegree to devices is not possible." );
473 }
474
475 NodeCollection::const_iterator target_begin = target_nc->rank_local_begin();
476 NodeCollection::const_iterator target_end = target_nc->end();
477
478 // protect against connecting to devices without proxies
479 // we need to do this before creating the first connection to leave
480 // the network untouched if any target does not have proxies
481 for ( NodeCollection::const_iterator tgt_it = target_begin; tgt_it < target_end; ++tgt_it )
482 {
483 Node* const tgt = kernel().node_manager.get_node_or_proxy( ( *tgt_it ).node_id );
484
485 assert( not tgt->is_proxy() );
486 }
487
488 if ( mask_.get() )
489 {
490 MaskedLayer< D > masked_source( source, mask_, allow_oversized_, source_nc );
491 const auto masked_source_end = masked_source.end();
492
493 std::vector< std::pair< Position< D >, size_t > > positions;
494
495 for ( NodeCollection::const_iterator tgt_it = target_begin; tgt_it < target_end; ++tgt_it )
496 {
497 size_t target_id = ( *tgt_it ).node_id;
498 Node* const tgt = kernel().node_manager.get_node_or_proxy( target_id );
499
500 size_t target_thread = tgt->get_thread();
501 RngPtr rng = get_vp_specific_rng( target_thread );
502 Position< D > target_pos = target.get_position( ( *tgt_it ).nc_index );
503
504 // We create a source pos vector here that can be updated with the
505 // source position. This is done to avoid creating and destroying
506 // unnecessarily many vectors.
507 std::vector< double > source_pos_vector( D );
508 const std::vector< double > target_pos_vector = target_pos.get_vector();
509
510 unsigned long target_number_connections =
511 std::round( number_of_connections_->value( rng, source_pos_vector, target_pos_vector, source, tgt ) );
512
513 // Get (position,node ID) pairs for sources inside mask
514 positions.resize( std::distance( masked_source.begin( target_pos ), masked_source_end ) );
515 std::copy( masked_source.begin( target_pos ), masked_source_end, positions.begin() );
516
517 // We will select `number_of_connections_` sources within the mask.
518 // If there is no kernel, we can just draw uniform random numbers,
519 // but with a kernel we have to set up a probability distribution
520 // function using a discrete_distribution.
521 if ( kernel_ )
522 {
523
524 std::vector< double > probabilities;
525 probabilities.reserve( positions.size() );
526
527 // Collect probabilities for the sources
528 for ( typename std::vector< std::pair< Position< D >, size_t > >::iterator iter = positions.begin();
529 iter != positions.end();
530 ++iter )
531 {
532 iter->first.get_vector( source_pos_vector );
533 probabilities.push_back( kernel_->value( rng, source_pos_vector, target_pos_vector, source, tgt ) );
534 }
535
536 if ( positions.empty()
537 or ( not allow_autapses_ and ( positions.size() == 1 ) and positions[ 0 ].second == target_id )
538 or ( not allow_multapses_ and ( positions.size() < target_number_connections ) ) )
539 {
540 std::string msg = String::compose( "Global target ID %1: Not enough sources found inside mask", target_id );
541 throw KernelException( msg.c_str() );
542 }
543
544 // A discrete_distribution draws random integers with a non-uniform
545 // distribution.
546 discrete_distribution lottery;
547 const discrete_distribution::param_type param( probabilities.begin(), probabilities.end() );
548 lottery.param( param );
549
550 // If multapses are not allowed, we must keep track of which
551 // sources have been selected already.
552 std::vector< bool > is_selected( positions.size() );
553
554 // Draw `target_number_connections` sources
555 while ( target_number_connections > 0 )
556 {
557 size_t random_id = lottery( rng );
558 if ( not allow_multapses_ and is_selected[ random_id ] )
559 {
560 continue;
561 }
562
563 size_t source_id = positions[ random_id ].second;
564 if ( not allow_autapses_ and source_id == target_id )
565 {
566 continue;
567 }
568 positions[ random_id ].first.get_vector( source_pos_vector );
569 for ( size_t indx = 0; indx < synapse_model_.size(); ++indx )
570 {
571 const double w = weight_[ indx ]->value( rng, source_pos_vector, target_pos_vector, source, tgt );
572 const double d = delay_[ indx ]->value( rng, source_pos_vector, target_pos_vector, source, tgt );
574 source_id, tgt, target_thread, synapse_model_[ indx ], param_dicts_[ indx ][ target_thread ], d, w );
575 }
576
577 is_selected[ random_id ] = true;
578 --target_number_connections;
579 }
580 }
581 else
582 {
583
584 // no kernel
585
586 if ( positions.empty()
587 or ( not allow_autapses_ and ( positions.size() == 1 ) and positions[ 0 ].second == target_id )
588 or ( not allow_multapses_ and ( positions.size() < target_number_connections ) ) )
589 {
590 std::string msg = String::compose( "Global target ID %1: Not enough sources found inside mask", target_id );
591 throw KernelException( msg.c_str() );
592 }
593
594 // If multapses are not allowed, we must keep track of which
595 // sources have been selected already.
596 std::vector< bool > is_selected( positions.size() );
597
598 // Draw `target_number_connections` sources
599 while ( target_number_connections > 0 )
600 {
601 const size_t random_id = rng->ulrand( positions.size() );
602 if ( not allow_multapses_ and is_selected[ random_id ] )
603 {
604 continue;
605 }
606 positions[ random_id ].first.get_vector( source_pos_vector );
607 const size_t source_id = positions[ random_id ].second;
608 for ( size_t indx = 0; indx < synapse_model_.size(); ++indx )
609 {
610 const double w = weight_[ indx ]->value( rng, source_pos_vector, target_pos_vector, source, tgt );
611 const double d = delay_[ indx ]->value( rng, source_pos_vector, target_pos_vector, source, tgt );
613 source_id, tgt, target_thread, synapse_model_[ indx ], param_dicts_[ indx ][ target_thread ], d, w );
614 }
615
616 is_selected[ random_id ] = true;
617 --target_number_connections;
618 }
619 }
620 }
621 }
622 else
623 {
624 // no mask
625
626 // Get (position,node ID) pairs for all nodes in source layer
627 std::vector< std::pair< Position< D >, size_t > >* positions = source.get_global_positions_vector( source_nc );
628
629 for ( NodeCollection::const_iterator tgt_it = target_begin; tgt_it < target_end; ++tgt_it )
630 {
631 size_t target_id = ( *tgt_it ).node_id;
632 Node* const tgt = kernel().node_manager.get_node_or_proxy( target_id );
633 size_t target_thread = tgt->get_thread();
634 RngPtr rng = get_vp_specific_rng( target_thread );
635 Position< D > target_pos = target.get_position( ( *tgt_it ).nc_index );
636
637 unsigned long target_number_connections = std::round( number_of_connections_->value( rng, tgt ) );
638
639 std::vector< double > source_pos_vector( D );
640 const std::vector< double > target_pos_vector = target_pos.get_vector();
641
642 if ( ( positions->size() == 0 )
643 or ( not allow_autapses_ and ( positions->size() == 1 ) and ( ( *positions )[ 0 ].second == target_id ) )
644 or ( not allow_multapses_ and ( positions->size() < target_number_connections ) ) )
645 {
646 std::string msg = String::compose( "Global target ID %1: Not enough sources found", target_id );
647 throw KernelException( msg.c_str() );
648 }
649
650 // We will select `target_number_connections` sources within the mask.
651 // If there is no kernel, we can just draw uniform random numbers,
652 // but with a kernel we have to set up a probability distribution
653 // function using a discrete_distribution.
654 if ( kernel_ )
655 {
656
657 std::vector< double > probabilities;
658 probabilities.reserve( positions->size() );
659
660 // Collect probabilities for the sources
661 for ( typename std::vector< std::pair< Position< D >, size_t > >::iterator iter = positions->begin();
662 iter != positions->end();
663 ++iter )
664 {
665 iter->first.get_vector( source_pos_vector );
666 probabilities.push_back( kernel_->value( rng, source_pos_vector, target_pos_vector, source, tgt ) );
667 }
668
669 // A discrete_distribution draws random integers with a non-uniform
670 // distribution.
671 discrete_distribution lottery;
672 const discrete_distribution::param_type param( probabilities.begin(), probabilities.end() );
673 lottery.param( param );
674
675 // If multapses are not allowed, we must keep track of which
676 // sources have been selected already.
677 std::vector< bool > is_selected( positions->size() );
678
679 // Draw `target_number_connections` sources
680 while ( target_number_connections > 0 )
681 {
682 const size_t random_id = lottery( rng );
683 if ( not allow_multapses_ and is_selected[ random_id ] )
684 {
685 continue;
686 }
687
688 const size_t source_id = ( *positions )[ random_id ].second;
689 if ( not allow_autapses_ and source_id == target_id )
690 {
691 continue;
692 }
693
694 ( *positions )[ random_id ].first.get_vector( source_pos_vector );
695 for ( size_t indx = 0; indx < synapse_model_.size(); ++indx )
696 {
697 const double w = weight_[ indx ]->value( rng, source_pos_vector, target_pos_vector, source, tgt );
698 const double d = delay_[ indx ]->value( rng, source_pos_vector, target_pos_vector, source, tgt );
700 source_id, tgt, target_thread, synapse_model_[ indx ], param_dicts_[ indx ][ target_thread ], d, w );
701 }
702
703 is_selected[ random_id ] = true;
704 --target_number_connections;
705 }
706 }
707 else
708 {
709
710 // no kernel
711
712 // If multapses are not allowed, we must keep track of which
713 // sources have been selected already.
714 std::vector< bool > is_selected( positions->size() );
715
716 // Draw `target_number_connections` sources
717 while ( target_number_connections > 0 )
718 {
719 const size_t random_id = rng->ulrand( positions->size() );
720 if ( not allow_multapses_ and is_selected[ random_id ] )
721 {
722 continue;
723 }
724
725 const size_t source_id = ( *positions )[ random_id ].second;
726 if ( not allow_autapses_ and source_id == target_id )
727 {
728 continue;
729 }
730
731 ( *positions )[ random_id ].first.get_vector( source_pos_vector );
732 for ( size_t indx = 0; indx < synapse_model_.size(); ++indx )
733 {
734 const double w = weight_[ indx ]->value( rng, source_pos_vector, target_pos_vector, source, tgt );
735 const double d = delay_[ indx ]->value( rng, source_pos_vector, target_pos_vector, source, tgt );
737 source_id, tgt, target_thread, synapse_model_[ indx ], param_dicts_[ indx ][ target_thread ], d, w );
738 }
739
740 is_selected[ random_id ] = true;
741 --target_number_connections;
742 }
743 }
744 }
745 }
746}
747
748
749template < int D >
750void
752 NodeCollectionPTR source_nc,
753 Layer< D >& target,
754 NodeCollectionPTR target_nc )
755{
756 // protect against connecting to devices without proxies
757 // we need to do this before creating the first connection to leave
758 // the network untouched if any target does not have proxies
759
760 // We only need to check the first in the NodeCollection
761 Node* const first_in_tgt = kernel().node_manager.get_node_or_proxy( target_nc->operator[]( 0 ) );
762 if ( not first_in_tgt->has_proxies() )
763 {
764 throw IllegalConnection( "Spatial Connect with fixed_outdegree to devices is not possible." );
765 }
766
767 NodeCollection::const_iterator target_begin = target_nc->rank_local_begin();
768 NodeCollection::const_iterator target_end = target_nc->end();
769
770 for ( NodeCollection::const_iterator tgt_it = target_begin; tgt_it < target_end; ++tgt_it )
771 {
772 Node* const tgt = kernel().node_manager.get_node_or_proxy( ( *tgt_it ).node_id );
773
774 assert( not tgt->is_proxy() );
775 }
776
777 // Fixed_outdegree connections (fixed fan out)
778 //
779 // For each (global) source: (All connections made on all mpi procs)
780 // 1. Apply mask to global targets
781 // 2. If using kernel: Compute connection probability for each global target
782 // 3. Draw connections to make using global rng
783
784 MaskedLayer< D > masked_target( target, mask_, allow_oversized_, target_nc );
785 const auto masked_target_end = masked_target.end();
786
787 // We create a target positions vector here that can be updated with the
788 // position and node ID pairs. This is done to avoid creating and destroying
789 // unnecessarily many vectors.
790 std::vector< std::pair< Position< D >, size_t > > target_pos_node_id_pairs;
791 std::vector< std::pair< Position< D >, size_t > > source_pos_node_id_pairs =
792 *source.get_global_positions_vector( source_nc );
793
794 for ( const auto& source_pos_node_id_pair : source_pos_node_id_pairs )
795 {
796 const Position< D > source_pos = source_pos_node_id_pair.first;
797 const size_t source_id = source_pos_node_id_pair.second;
798 const auto src = kernel().node_manager.get_node_or_proxy( source_id );
799 const std::vector< double > source_pos_vector = source_pos.get_vector();
800
801 // We create a target pos vector here that can be updated with the
802 // target position. This is done to avoid creating and destroying
803 // unnecessarily many vectors.
804 std::vector< double > target_pos_vector( D );
805 std::vector< double > probabilities;
806
807 // Find potential targets and probabilities
809 target_pos_node_id_pairs.resize( std::distance( masked_target.begin( source_pos ), masked_target_end ) );
810 std::copy( masked_target.begin( source_pos ), masked_target_end, target_pos_node_id_pairs.begin() );
811
812 probabilities.reserve( target_pos_node_id_pairs.size() );
813 if ( kernel_ )
814 {
815 for ( const auto& target_pos_node_id_pair : target_pos_node_id_pairs )
816 {
817 // TODO: Why is probability calculated in source layer, but weight and delay in target layer?
818 target_pos_node_id_pair.first.get_vector( target_pos_vector );
819 const auto tgt = kernel().node_manager.get_node_or_proxy( target_pos_node_id_pair.second );
820 probabilities.push_back( kernel_->value( grng, source_pos_vector, target_pos_vector, source, tgt ) );
821 }
822 }
823 else
824 {
825 probabilities.resize( target_pos_node_id_pairs.size(), 1.0 );
826 }
827
828 unsigned long number_of_connections = std::round( number_of_connections_->value( grng, src ) );
829
830 if ( target_pos_node_id_pairs.empty()
831 or ( not allow_multapses_ and target_pos_node_id_pairs.size() < number_of_connections ) )
832 {
833 std::string msg = String::compose( "Global source ID %1: Not enough targets found", source_id );
834 throw KernelException( msg.c_str() );
835 }
836
837 // Draw targets. A discrete_distribution draws random integers with a
838 // non-uniform distribution.
839 discrete_distribution lottery;
840 const discrete_distribution::param_type param( probabilities.begin(), probabilities.end() );
841 lottery.param( param );
842
843 // If multapses are not allowed, we must keep track of which
844 // targets have been selected already.
845 std::vector< bool > is_selected( target_pos_node_id_pairs.size() );
846
847 // Draw `number_of_connections` targets
848 while ( number_of_connections > 0 )
849 {
850 const size_t random_id = lottery( get_rank_synced_rng() );
851 if ( not allow_multapses_ and is_selected[ random_id ] )
852 {
853 continue;
854 }
855 const size_t target_id = target_pos_node_id_pairs[ random_id ].second;
856 if ( not allow_autapses_ and source_id == target_id )
857 {
858 continue;
859 }
860
861 is_selected[ random_id ] = true;
862
863 target_pos_node_id_pairs[ random_id ].first.get_vector( target_pos_vector );
864
865 std::vector< double > rng_weight_vec;
866 std::vector< double > rng_delay_vec;
867 for ( size_t indx = 0; indx < weight_.size(); ++indx )
868 {
869 const auto tgt = kernel().node_manager.get_node_or_proxy( target_pos_node_id_pairs[ indx ].second );
870 rng_weight_vec.push_back( weight_[ indx ]->value( grng, source_pos_vector, target_pos_vector, target, tgt ) );
871 rng_delay_vec.push_back( delay_[ indx ]->value( grng, source_pos_vector, target_pos_vector, target, tgt ) );
872 }
873
874 // Each VP has now decided to create this connection and drawn any random parameter values
875 // required for it. Each VP thus counts the connection as created, but only the VP hosting the
876 // target neuron actually creates the connection.
877 --number_of_connections;
878 if ( not kernel().node_manager.is_local_node_id( target_id ) )
879 {
880 continue;
881 }
882
883 Node* target_ptr = kernel().node_manager.get_node_or_proxy( target_id );
884 const size_t target_thread = target_ptr->get_thread();
885
886 for ( size_t indx = 0; indx < synapse_model_.size(); ++indx )
887 {
888 kernel().connection_manager.connect( source_id,
889 target_ptr,
890 target_thread,
891 synapse_model_[ indx ],
892 param_dicts_[ indx ][ target_thread ],
893 rng_delay_vec[ indx ],
894 rng_weight_vec[ indx ] );
895 }
896 }
897 }
898}
899
900} // namespace nest
901
902#endif
Exception to be thrown if a status parameter is incomplete or inconsistent.
Definition exceptions.h:680
Base class for RNG engine wrappers.
Definition random_generators.h:67
virtual unsigned long ulrand(unsigned long N)=0
Uses the wrapped RNG engine to draw an unsigned long from a uniform distribution in the range [0,...
virtual double drand()=0
Uses the wrapped RNG engine to draw a double from a uniform distribution in the range [0,...
Wrapper for masked and unmasked pools.
Definition connection_creator.h:116
void define(MaskedLayer< D > *)
Definition connection_creator_impl.h:179
Ntree< D, size_t >::masked_iterator masked_begin(const Position< D > &pos) const
Definition connection_creator_impl.h:199
~PoolWrapper_()
Definition connection_creator_impl.h:169
std::vector< std::pair< Position< D >, size_t > >::iterator begin() const
Definition connection_creator_impl.h:213
Ntree< D, size_t >::masked_iterator masked_end() const
Definition connection_creator_impl.h:206
PoolWrapper_()
Definition connection_creator_impl.h:162
std::vector< std::pair< Position< D >, size_t > >::iterator end() const
Definition connection_creator_impl.h:220
void pairwise_bernoulli_on_source_(Layer< D > &source, NodeCollectionPTR source_nc, Layer< D > &target, NodeCollectionPTR target_nc)
Definition connection_creator_impl.h:228
void pairwise_poisson_(Layer< D > &source, NodeCollectionPTR source_nc, Layer< D > &target, NodeCollectionPTR target_nc)
Definition connection_creator_impl.h:385
void connect_to_target_poisson_(Iterator from, Iterator to, Node *tgt_ptr, const Position< D > &tgt_pos, size_t tgt_thread, const Layer< D > &source)
Definition connection_creator_impl.h:118
MaskPTR mask_
Definition connection_creator.h:181
std::vector< std::vector< Dictionary > > param_dicts_
Definition connection_creator.h:184
void connect_to_target_(Iterator from, Iterator to, Node *tgt_ptr, const Position< D > &tgt_pos, size_t tgt_thread, const Layer< D > &source)
Definition connection_creator_impl.h:77
@ Pairwise_bernoulli_on_source
Definition connection_creator.h:67
@ Pairwise_poisson
Definition connection_creator.h:69
@ Pairwise_bernoulli_on_target
Definition connection_creator.h:68
@ Fixed_outdegree
Definition connection_creator.h:71
@ Fixed_indegree
Definition connection_creator.h:70
std::vector< ParameterPTR > weight_
Definition connection_creator.h:185
ParameterPTR number_of_connections_
Definition connection_creator.h:180
std::vector< ParameterPTR > delay_
Definition connection_creator.h:186
ParameterPTR kernel_
Definition connection_creator.h:182
void fixed_indegree_(Layer< D > &source, NodeCollectionPTR source_nc, Layer< D > &target, NodeCollectionPTR target_nc)
Definition connection_creator_impl.h:456
bool allow_autapses_
Definition connection_creator.h:177
void pairwise_bernoulli_on_target_(Layer< D > &source, NodeCollectionPTR source_nc, Layer< D > &target, NodeCollectionPTR target_nc)
Definition connection_creator_impl.h:299
bool allow_oversized_
Definition connection_creator.h:179
void connect(Layer< D > &source, NodeCollectionPTR source_nc, Layer< D > &target, NodeCollectionPTR target_nc)
Connect two layers.
Definition connection_creator_impl.h:38
ConnectionType type_
Definition connection_creator.h:176
std::vector< size_t > synapse_model_
Definition connection_creator.h:183
void fixed_outdegree_(Layer< D > &source, NodeCollectionPTR source_nc, Layer< D > &target, NodeCollectionPTR target_nc)
Definition connection_creator_impl.h:751
bool allow_multapses_
Definition connection_creator.h:178
void connect(NodeCollectionPTR sources, NodeCollectionPTR targets, const Dictionary &conn_spec, const std::vector< Dictionary > &syn_specs)
Create connections.
Definition connection_manager.cpp:431
To be thrown if a connection is not possible.
Definition exceptions.h:490
Base class for all Kernel exceptions.
Definition exceptions.h:65
Abstract base class for Layer of given dimension (D=2 or 3).
Definition layer.h:218
Class for applying masks to layers.
Definition layer.h:458
Ntree< D, size_t >::masked_iterator begin(const Position< D > &anchor)
Iterate over nodes inside mask.
Definition layer.h:570
Ntree< D, size_t >::masked_iterator end()
Definition layer.h:584
Node * get_node_or_proxy(size_t node_id, size_t tid)
Return pointer to the specified Node.
Definition node_manager.cpp:429
Base class for all NEST network objects.
Definition node.h:99
virtual bool has_proxies() const
Returns true if the node has proxies on remote threads.
Definition node.h:1164
size_t get_thread() const
Retrieve the number of the thread to which the node is assigned.
Definition node.h:1238
virtual bool is_proxy() const
Returns true if the node is a proxy node.
Definition node.h:1188
size_t get_node_id() const
Return global Network ID.
Definition node.h:1200
Iterator iterating the nodes in a Quadtree inside a Mask.
Definition ntree.h:153
Definition position.h:57
const std::vector< T > get_vector() const
Definition position.h:501
typename DistributionT::param_type param_type
Definition random_generators.h:373
void param(const param_type &params)
Sets the distribution's associated parameter set to params.
Definition random_generators.h:420
size_t get_thread_id() const
Gets ID of local thread.
Definition vp_manager.h:176
Iterator for NodeCollections.
Definition node_collection.h:415
ConnectionManager connection_manager
Definition kernel_manager.h:239
NodeManager node_manager
Definition kernel_manager.h:245
VPManager vp_manager
Definition kernel_manager.h:234
Namespace for the NEST simulation kernel.
Definition beta_normalization_factor.h:33
RngPtr get_vp_specific_rng(size_t tid)
Definition kernel_manager.h:298
RngPtr get_rank_synced_rng()
Definition kernel_manager.h:286
KernelManager & kernel()
Definition kernel_manager.h:311
std::shared_ptr< NodeCollection > NodeCollectionPTR
Definition node_collection.h:50