NEST main@caf0ae8
 
Loading...
Searching...
No Matches
ntree_impl.h
Go to the documentation of this file.
1/*
2 * ntree_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 NTREE_IMPL_H
24#define NTREE_IMPL_H
25
26#include <limits>
27
28#include "ntree.h"
29
30// Includes from spatial:
31#include "mask.h"
32
33namespace nest
34{
35
36template < int D, class T, int max_capacity, int max_depth >
38 : ntree_( &q )
39 , top_( &q )
40 , node_( 0 )
41{
42 // First leaf
43 while ( not ntree_->is_leaf() )
44 {
45 ntree_ = ntree_->children_[ 0 ];
46 }
47 // Find the first non-empty leaf
48 while ( ntree_->nodes_.empty() )
49 {
50
51 next_leaf_();
52 if ( ntree_ == 0 )
53 {
54 break;
55 }
56 }
57}
58
59template < int D, class T, int max_capacity, int max_depth >
62{
63 node_++;
64
65 while ( node_ >= ntree_->nodes_.size() )
66 {
67
68 next_leaf_();
69
70 node_ = 0;
71 if ( ntree_ == 0 )
72 {
73 break;
74 }
75 }
76
77 return *this;
78}
79
80template < int D, class T, int max_capacity, int max_depth >
81void
83{
84
85 // If we are on the last subntree, move up
86 while ( ntree_ and ( ntree_ != top_ ) and ntree_->my_subquad_ == N - 1 )
87 {
88 ntree_ = ntree_->parent_;
89 }
90
91 // Since we stop at the top, this should never happen!
92 assert( ntree_ != 0 );
93
94 // If we have reached the top, mark as invalid and return
95 if ( ntree_ == top_ )
96 {
97 ntree_ = 0;
98 return;
99 }
100
101 // Move to next sibling
102 ntree_ = ntree_->parent_->children_[ ntree_->my_subquad_ + 1 ];
103
104 // Move down if this is not a leaf.
105 while ( not ntree_->is_leaf() )
106 {
107 ntree_ = ntree_->children_[ 0 ];
108 }
109}
110
111// Proper mod which returns non-negative numbers
112static inline double
113mod( double x, double p )
114{
115 x = std::fmod( x, p );
116 if ( x < 0 )
117 {
118 x += p;
119 }
120 return x;
121}
122
123template < int D, class T, int max_capacity, int max_depth >
125 const Mask< D >& mask,
126 const Position< D >& anchor )
127 : ntree_( &q )
128 , top_( &q )
129 , allin_top_( 0 )
130 , node_( 0 )
131 , mask_( &mask )
132 , anchor_( anchor )
133 , anchors_()
134 , current_anchor_( 0 )
135{
136 if ( ntree_->periodic_.any() )
137 {
138 Box< D > mask_bb = mask_->get_bbox();
139
140 // Move lower left corner of mask into main image of layer
141 for ( int i = 0; i < D; ++i )
142 {
143 if ( ntree_->periodic_[ i ] )
144 {
145 anchor_[ i ] = mod( anchor_[ i ] + mask_bb.lower_left[ i ] - ntree_->lower_left_[ i ], ntree_->extent_[ i ] )
146 - mask_bb.lower_left[ i ] + ntree_->lower_left_[ i ];
147 }
148 }
149 anchors_.push_back( anchor_ );
150
151 // Add extra anchors for each dimension where this is needed
152 // (Assumes that the mask is not wider than the layer)
153 for ( int i = 0; i < D; ++i )
154 {
155 if ( ntree_->periodic_[ i ] )
156 {
157 int n = anchors_.size();
158 if ( ( anchor_[ i ] + mask_bb.upper_right[ i ] - ntree_->lower_left_[ i ] ) > ntree_->extent_[ i ] )
159 {
160 for ( int j = 0; j < n; ++j )
161 {
162 Position< D > p = anchors_[ j ];
163 p[ i ] -= ntree_->extent_[ i ];
164 anchors_.push_back( p );
165 }
166 }
167 }
168 }
169 }
170
171 init_();
172}
173
174template < int D, class T, int max_capacity, int max_depth >
175void
177{
178 node_ = 0;
179 allin_top_ = 0;
180 ntree_ = top_;
181
182 if ( mask_->outside( Box< D >( ntree_->lower_left_ - anchor_, ntree_->lower_left_ - anchor_ + ntree_->extent_ ) ) )
183 {
184
185 next_anchor_();
186 }
187 else
188 {
189
190 if ( mask_->inside( Box< D >( ntree_->lower_left_ - anchor_, ntree_->lower_left_ - anchor_ + ntree_->extent_ ) ) )
191 {
192 first_leaf_inside_();
193 }
194 else
195 {
196 first_leaf_();
197 }
198
199 if ( ntree_->nodes_.empty() or ( not mask_->inside( ntree_->nodes_[ node_ ].first - anchor_ ) ) )
200 {
201 ++( *this );
202 }
203 }
204}
205
206template < int D, class T, int max_capacity, int max_depth >
207void
209{
210 ++current_anchor_;
211 if ( current_anchor_ >= anchors_.size() )
212 {
213 // Done. Mark as invalid.
214 ntree_ = 0;
215 node_ = 0;
216 }
217 else
218 {
219 anchor_ = anchors_[ current_anchor_ ];
220 init_();
221 }
222}
223
224template < int D, class T, int max_capacity, int max_depth >
225void
227{
228
229 // There are two states: the initial state, and "all in". In the
230 // all in state, we are in a subtree which is completely inside
231 // the mask. The allin_top_ is the top of this subtree. When
232 // exiting the subtree, the state changes to the initial
233 // state. In the initial state, we must check each quadrant to
234 // see if it is completely inside or outside the mask. If inside,
235 // we go all in. If outside, we move on to the next leaf. If
236 // neither, keep going until we find a leaf. Upon exiting from
237 // this function, we are either done (ntree_==0), or on a leaf
238 // node which at least intersects with the mask. If allin_top_!=0,
239 // the leaf is completely inside the mask.
240
241 if ( allin_top_ )
242 {
243 // state: all in
244
245 // If we are on the last subtree, move up
246 while ( ntree_ and ( ntree_ != allin_top_ ) and ntree_->my_subquad_ == N - 1 )
247 {
248 ntree_ = ntree_->parent_;
249 }
250
251 // Since we stop at the top, this should never happen!
252 assert( ntree_ != 0 );
253
254 // If we reached the allin_top_, we are no longer all in.
255 if ( ntree_ != allin_top_ )
256 {
257
258 // Move to next sibling
259 ntree_ = ntree_->parent_->children_[ ntree_->my_subquad_ + 1 ];
260
261 // Move down if this is not a leaf.
262 while ( not ntree_->is_leaf() )
263 {
264 ntree_ = ntree_->children_[ 0 ];
265 }
266 return;
267 }
268
269 allin_top_ = 0;
270 // Will continue as not all in.
271 }
272
273 // state: Not all in
274
275 do
276 {
277
278 // If we are on the last subtree, move up
279 while ( ntree_ and ( ntree_ != top_ ) and ntree_->my_subquad_ == N - 1 )
280 {
281 ntree_ = ntree_->parent_;
282 }
283
284 // Since we stop at the top, this should never happen!
285 assert( ntree_ != 0 );
286
287 // If we have reached the top, mark as invalid and return
288 if ( ntree_ == top_ )
289 {
290 return next_anchor_();
291 }
292
293 // Move to next sibling
294 ntree_ = ntree_->parent_->children_[ ntree_->my_subquad_ + 1 ];
295 // Create anchored position in two steps to avoid creating a new Position object.
296 anchored_position_ = ntree_->lower_left_;
297 anchored_position_ -= anchor_;
298
299 if ( mask_->inside( Box< D >( anchored_position_, anchored_position_ + ntree_->extent_ ) ) )
300 {
301 return first_leaf_inside_();
302 }
303
304 } while ( mask_->outside( Box< D >( anchored_position_, anchored_position_ + ntree_->extent_ ) ) );
305
306 return first_leaf_();
307}
308
309template < int D, class T, int max_capacity, int max_depth >
310void
312{
313 while ( not ntree_->is_leaf() )
314 {
315
316 ntree_ = ntree_->children_[ 0 ];
317
318 if ( mask_->inside( Box< D >( ntree_->lower_left_ - anchor_, ntree_->lower_left_ - anchor_ + ntree_->extent_ ) ) )
319 {
320 return first_leaf_inside_();
321 }
322
323 if ( mask_->outside( Box< D >( ntree_->lower_left_ - anchor_, ntree_->lower_left_ - anchor_ + ntree_->extent_ ) ) )
324 {
325 return next_leaf_();
326 }
327 }
328}
329
330
331template < int D, class T, int max_capacity, int max_depth >
332void
334{
335
336 allin_top_ = ntree_;
337
338 while ( not ntree_->is_leaf() )
339 {
340 ntree_ = ntree_->children_[ 0 ];
341 }
342}
343
344template < int D, class T, int max_capacity, int max_depth >
347{
348 ++node_;
349
350 if ( allin_top_ == 0 )
351 {
352 while (
353 ( node_ < ntree_->nodes_.size() ) and ( not anchored_position_inside_mask( ntree_->nodes_[ node_ ].first ) ) )
354 {
355 ++node_;
356 }
357 }
358
359 while ( node_ >= ntree_->nodes_.size() )
360 {
361 next_leaf_();
362
363 node_ = 0;
364 if ( ntree_ == 0 )
365 {
366 break;
367 }
368
369 if ( allin_top_ == 0 )
370 {
371 while (
372 ( node_ < ntree_->nodes_.size() ) and ( not anchored_position_inside_mask( ntree_->nodes_[ node_ ].first ) ) )
373 {
374 ++node_;
375 }
376 }
377 }
378
379 return *this;
380}
381
382template < int D, class T, int max_capacity, int max_depth >
383int
385{
386 int r = 0;
387 for ( int i = 0; i < D; ++i )
388 {
389 // Comparing against an epsilon value in case there are round-off errors.
390 // Using a negative epsilon value because the round-off error may go both ways
391 // and the difference we check against may therefore be +/- 10^-16.
392 const bool in_left_half =
393 ( ( lower_left_[ i ] + extent_[ i ] / 2 ) - pos[ i ] ) > -std::numeric_limits< double >::epsilon();
394 r += ( 1 << i ) * ( in_left_half ? 0 : 1 );
395 }
396
397 return r;
398}
399
400template < int D, class T, int max_capacity, int max_depth >
401void
403{
404 if ( leaf_ )
405 {
406 std::copy( nodes_.begin(), nodes_.end(), std::back_inserter( v ) );
407 }
408 else
409 {
410 for ( int i = 0; i < N; ++i )
411 {
412 children_[ i ]->append_nodes_( v );
413 }
414 }
415}
416
417template < int D, class T, int max_capacity, int max_depth >
418void
419Ntree< D, T, max_capacity, max_depth >::append_nodes_( std::vector< std::pair< Position< D >, T > >& v,
420 const Mask< D >& mask,
421 const Position< D >& anchor )
422{
423 if ( mask.outside( Box< D >( lower_left_ - anchor, lower_left_ - anchor + extent_ ) ) )
424 {
425 return;
426 }
427 if ( mask.inside( Box< D >( lower_left_ - anchor, lower_left_ - anchor + extent_ ) ) )
428 {
429 return append_nodes_( v );
430 }
431 if ( leaf_ )
432 {
433
434 for ( typename std::vector< std::pair< Position< D >, T > >::iterator i = nodes_.begin(); i != nodes_.end(); ++i )
435 {
436 if ( mask.inside( i->first - anchor ) )
437 {
438 v.push_back( *i );
439 }
440 }
441 }
442 else
443 {
444 for ( int i = 0; i < N; ++i )
445 {
446 children_[ i ]->append_nodes_( v, mask, anchor );
447 }
448 }
449}
450
451template < int D, class T, int max_capacity, int max_depth >
452typename Ntree< D, T, max_capacity, max_depth >::iterator
454{
455 if ( periodic_.any() )
456 {
457 // Map position into standard range when using periodic b.c. Only necessary when
458 // inserting positions during source driven connect when target has periodic b.c.
459 // May be inefficient.
460 for ( int i = 0; i < D; ++i )
461 {
462 if ( periodic_[ i ] )
463 {
464 pos[ i ] = lower_left_[ i ] + std::fmod( pos[ i ] - lower_left_[ i ], extent_[ i ] );
465 if ( pos[ i ] < lower_left_[ i ] )
466 {
467 pos[ i ] += extent_[ i ];
468 }
469 }
470 }
471 }
472
473 if ( leaf_ and ( nodes_.size() >= max_capacity ) and my_depth_ < max_depth )
474 {
475 split_();
476 }
477 if ( leaf_ )
478 {
479
480 for ( int i = 0; i < D; ++i )
481 {
482 // Comparing against an epsilon value in case there are round-off errors.
483 // Using a negative epsilon value because the round-off error may go both ways
484 // and the difference we check against may therefore be +/- 10^-16.
485 assert( ( pos - lower_left_ )[ i ] > -std::numeric_limits< double >::epsilon()
486 and ( lower_left_ + extent_ - pos )[ i ] > -std::numeric_limits< double >::epsilon() );
487 }
488
489 nodes_.push_back( std::pair< Position< D >, T >( pos, node ) );
490
491 return iterator( *this, nodes_.size() - 1 );
492 }
493 else
494 {
495
496 return children_[ subquad_( pos ) ]->insert( pos, node );
497 }
498}
499
500template < int D, class T, int max_capacity, int max_depth >
501void
503{
504 assert( leaf_ );
505
506 for ( int j = 0; j < N; ++j )
507 {
508 Position< D > lower_left = lower_left_;
509 for ( int i = 0; i < D; ++i )
510 {
511 if ( j & ( 1 << i ) )
512 {
513 lower_left[ i ] += extent_[ i ] * 0.5;
514 }
515 }
516
517 children_[ j ] = new Ntree< D, T, max_capacity, max_depth >( lower_left, extent_ * 0.5, 0, this, j );
518 }
519
520 for ( typename std::vector< std::pair< Position< D >, T > >::iterator i = nodes_.begin(); i != nodes_.end(); ++i )
521 {
522 children_[ subquad_( i->first ) ]->insert( i->first, i->second );
523 }
524
525 nodes_.clear();
526
527 leaf_ = false;
528}
529}
530
531#endif
Abstract base class for masks with given dimension.
Definition mask.h:101
Iterator iterating the nodes in a Quadtree.
Definition ntree.h:69
iterator & operator++()
Move the iterator to the next node within the tree.
Definition ntree_impl.h:61
Ntree * ntree_
Definition ntree.h:144
iterator()
Initialize an invalid iterator.
Definition ntree.h:74
void next_leaf_()
Move to the next leaf quadrant, or set ntree_ to 0 if there are no more leaves.
Definition ntree_impl.h:82
Iterator iterating the nodes in a Quadtree inside a Mask.
Definition ntree.h:153
Ntree * ntree_
Definition ntree.h:262
std::vector< Position< D > > anchors_
Definition ntree.h:269
void first_leaf_inside_()
Set the allin_top_ to the current quadrant, and find the first leaf below the current quadrant.
Definition ntree_impl.h:333
void init_()
Initialize.
Definition ntree_impl.h:176
masked_iterator & operator++()
Move the iterator to the next node inside the mask within the tree.
Definition ntree_impl.h:346
const Mask< D > * mask_
Definition ntree.h:266
masked_iterator()
Initialize an invalid iterator.
Definition ntree.h:163
Position< D > anchor_
Definition ntree.h:267
void next_leaf_()
Find the next leaf which is not outside the mask.
Definition ntree_impl.h:226
void next_anchor_()
Go to the next anchor image.
Definition ntree_impl.h:208
void first_leaf_()
Find the first leaf which is not outside the mask.
Definition ntree_impl.h:311
A Ntree object represents a subtree or leaf in a Ntree structure.
Definition ntree.h:55
iterator insert(Position< D > pos, const T &node)
Traverse quadtree structure from current ntree.
Definition ntree_impl.h:453
Position< D > lower_left_
Definition ntree.h:392
bool is_leaf() const
Definition ntree.h:457
Position< D > extent_
Definition ntree.h:393
void split_()
Change a leaf ntree to a regular ntree with four children regions.
Definition ntree_impl.h:502
int my_depth_
This Ntree's depth in the tree.
Definition ntree.h:401
int subquad_(const Position< D > &)
Definition ntree_impl.h:384
static const int N
Definition ntree.h:57
Ntree * children_[N]
Definition ntree.h:402
std::vector< value_type > nodes_
Definition ntree.h:397
std::bitset< D > periodic_
periodic b.c.
Definition ntree.h:403
void append_nodes_(std::vector< value_type > &)
Append this ntree's nodes to the vector.
bool leaf_
Definition ntree.h:395
Definition position.h:57
const std::string mask("mask")
const std::string v("v")
Namespace for the NEST simulation kernel.
Definition beta_normalization_factor.h:33
static double mod(double x, double p)
Definition ntree_impl.h:113
A box is defined by the lower left corner (minimum coordinates) and the upper right corner (maximum c...
Definition position.h:321
Position< D > lower_left
Definition position.h:331
Position< D > upper_right
Definition position.h:332