NEURON
bbtqueue.cpp
Go to the documentation of this file.
1 // balanced binary tree queue implemented by Michael Hines
2 
4  left_ = nil;
5  right_ = nil;
6  parent_ = nil;
7 }
8 
10  if (left_) {
11  delete left_;
12  }
13  if (right_) {
14  delete right_;
15  }
16 }
17 
18 static void deleteitem(TQItem* i) {
19  if (i->left_) {
20  deleteitem(i->left_);
21  }
22  if (i->right_) {
23  deleteitem(i->right_);
24  }
25  i->left_ = nil;
26  i->right_ = nil;
27  tpool_->free(i);
28 }
29 
30 bool TQItem::check() {
31 #if DOCHECK
32  if (left_ && left_->t_ > t_) {
33  printf("left %g not <= %g\n", left_->t_, t_);
34  return false;
35  }
36  if (right_ && right_->t_ < t_) {
37  printf("right %g not >= %g\n", right_->t_, t_);
38  return false;
39  }
40  if (parent_) {
41  if (parent_->left_ == this) {
42  if (t_ > parent_->t_) {
43  printf("%g not <= parent %g\n", t_, parent_->t_);
44  return false;
45  }
46  } else if (parent_->right_ == this) {
47  if (t_ < parent_->t_) {
48  printf("%g not >= parent %g\n", t_, parent_->t_);
49  return false;
50  }
51  } else {
52  printf("this %g is not a child of its parent %g\n", t_, parent_->t_);
53  return false;
54  }
55  }
56  if (w_ != wleft() + wright() + 1) {
57  printf("%g: weight %d inconsistent with left=%d and right=%d\n", t_, w_, wleft(), wright());
58  return false;
59  }
60 #endif
61  return true;
62 }
63 
64 static void prnt(const TQItem* b, int level) {
65  int i;
66  for (i = 0; i < level; ++i) {
67  Printf(" ");
68  }
69  Printf("%g %c %d\n", b->t_, b->data_ ? 'x' : 'o', b->w_);
70 }
71 
72 static void chk(TQItem* b, int level) {
73  if (!b->check()) {
74  hoc_execerror("chk failed", errmess_);
75  }
76 }
77 
78 void TQItem::t_iterate(void (*f)(const TQItem*, int), int level) {
79  if (left_) {
80  left_->t_iterate(f, level + 1);
81  }
82  f(this, level);
83  if (right_) {
84  right_->t_iterate(f, level + 1);
85  }
86 }
87 
88 #if BBTQ == 0 // balanced binary tree implemented by Michael Hines
89 
91  if (!tpool_) {
92  tpool_ = new TQItemPool(1000);
93  }
94  root_ = nil;
95  least_ = nil;
96 
97 #if COLLECT_TQueue_STATISTICS
98  nmove = ninsert = nrem = nleast = nbal = ncmplxrem = 0;
100 #endif
101 }
102 
104  if (root_) {
105  deleteitem(root_);
106  }
107 }
108 
110  if (root_) {
111  root_->t_iterate(prnt, 0);
112  }
113 }
114 
115 void TQueue::forall_callback(void (*f)(const TQItem*, int)) {
116  if (root_) {
117  root_->t_iterate(f, 0);
118  }
119 }
120 
121 void TQueue::check(const char* mes) {
122 #if DOCHECK
123  errmess_ = mes;
124  if (root_) {
125  root_->t_iterate(chk, 0);
126  }
127  errmess_ = nil;
128 #endif
129 }
130 
131 double TQueue::least_t() {
132  TQItem* b = least();
133  if (b) {
134  return b->t_;
135  } else {
136  return 1e15;
137  }
138 }
139 
141  STAT(nleast)
142 #if !FAST_LEAST || DOCHECK
143  TQItem* b;
144  b = root_;
145  if (b)
146  for (; b->left_; b = b->left_) {
148  }
149 #if DOCHECK
150  assert(least_ == b);
151 #else
152  least_ = b;
153 #endif
154 #endif
155  return least_;
156 }
157 
159  assert(least_);
160  assert(!least_->left_);
161  TQItem* b = least_->right_;
162  if (b) {
163  for (; b->left_; b = b->left_) {
164  ;
165  }
166  least_ = b;
167  } else {
168  b = least_->parent_;
169  if (b) {
170  assert(b->left_ == least_);
171  least_ = b;
172  } else {
173  least_ = nil;
174  }
175  }
176 }
177 
178 void TQueue::move_least(double tnew) {
179  TQItem* b = least();
180  if (b) {
181  move(b, tnew);
182  }
183 }
184 
185 void TQueue::move(TQItem* i, double tnew) {
186  PSTART(1)
187  STAT(nmove)
188 #if 0
189  // this is a bug
190  // check if it really needs moving
191  STAT(ncompare)
192  double tmin = -1e9, tmax = 1e9;
193  if (i->left_) {
194  tmin = i->left_->t_;
195  }else if (i->parent_ && i->parent_->right_ == i) {
196  tmin = i->parent_->t_;
197  }
198  if (i->right_) {
199  tmax = i->right_->t_;
200  }else if (i->parent_ && i->parent_->left_ == i) {
201  tmax = i->parent_->t_;
202  }
203  if ( tmin <= tnew && tnew < tmax) { // confusing to check equality
204  STAT(nfastmove)
205  i->t_ = tnew;
206 i->check();
207 PSTOP(1)
208  return;
209  }
210 #endif
211  // the long way
212  remove1(i);
213  insert1(tnew, i);
214  PSTOP(1)
215 }
216 
218  TQItem* b;
219  STAT(nfind)
220  for (b = root_; b;) {
221  STAT(nfindsrch)
222  STAT(ncompare)
223  if (t == b->t_) {
224  // printf("found %g\n", t);
225  return b;
226  } else if (t < b->t_) {
227  b = b->left_;
228  } else {
229  b = b->right_;
230  }
231  }
232  Printf("couldn't find %g\n", t);
233  return b;
234 }
235 
237  PSTART(1)
238  if (i) {
239  remove1(i);
240  deleteitem(i);
241  }
242  PSTOP(1)
243 }
244 
246  STAT(nrem)
247  // merely remove if leaf
248  // if no left, right becomes left of parent
249  // replace i with rightmost on left (say x)
250  // we could just replace i.data with x.data
251  // and remove x. But then, data holding pointer to
252  // x would be invalid. So take the trouble to reset
253  // pointer belonging to x
254  check("begin remove1");
255 #if FAST_LEAST
256  if (least_ && least_ == i) {
257  new_least();
258  }
259 #endif
260  TQItem* p = i->parent_;
261  TQItem** child;
262  bool doweight = true;
263  if (p) {
264  // printf("removing with a parent %g\n", i->t_);
265  if (p->left_ == i) {
266  child = &p->left_;
267  } else {
268  child = &p->right_;
269  }
270  }
271 
272  if (i->left_) {
273  STAT(ncmplxrem);
274  // printf("removing with a left %g\n", i->t_);
275  // replace i with rightmost on left
276  TQItem* x;
277  for (x = i->left_; x->right_; x = x->right_) {
278  ;
279  }
280  if (x == i->left_) {
281  // printf("x == i->left\n");
282  if (p) {
283  *child = x;
284  } else {
285  root_ = x;
286  }
287  x->parent_ = i->parent_;
288  x->right_ = i->right_;
289  if (x->right_) {
290  x->right_->parent_ = x;
291  // x->w_ += x->right_->w_;
292  x->w_ = i->w_ - 1;
293  }
294  } else {
295  remove1(x);
296  doweight = false;
297  if (p) {
298  *child = x;
299  } else {
300  root_ = x;
301  }
302  x->parent_ = i->parent_;
303  x->right_ = i->right_;
304  x->left_ = i->left_;
305  x->left_->parent_ = x;
306  if (x->right_) {
307  x->right_->parent_ = x;
308  }
309  x->w_ = i->w_;
310  }
311  } else if (i->right_) {
312  // printf("removing with a right but no left %g\n", i->t_);
313  // check(); printf("checked\n");
314  // no left
315  if (p) {
316  *child = i->right_;
317  (*child)->parent_ = p;
318  } else {
319  root_ = i->right_;
320  root_->parent_ = nil;
321  }
322  } else {
323  // a leaf
324  // printf("removing leaf %g\n", i->t_);
325  if (p) {
326  *child = nil;
327  } else {
328  root_ = nil;
329  }
330  }
331  if (doweight) {
332  while (p) {
333  --p->w_;
334  p = p->parent_;
335  }
336  }
337  i->right_ = nil;
338  i->left_ = nil;
339  i->parent_ = nil;
340  check("end remove1");
341 }
342 
343 void TQueue::reverse(TQItem* b) { // switch item and parent
344  TQItem* p = b->parent_;
345  if (p) {
346  STAT(nbal)
347  if (p->parent_) {
348  if (!p->parent_->check())
349  Printf("p->parent failed start\n");
350  }
351  if (!p->check())
352  Printf("p failed at start\n");
353  if (!b->check())
354  Printf("b failed at start\n");
355  if (p->parent_) {
356  b->parent_ = p->parent_;
357  if (p->parent_->left_ == p) {
358  p->parent_->left_ = b;
359  } else {
360  p->parent_->right_ = b;
361  }
362  } else {
363  assert(root_ == p);
364  b->parent_ = nil;
365  root_ = b;
366  }
367  b->w_ = p->w_;
368  p->parent_ = b;
369  if (p->left_ == b) {
370  p->left_ = b->right_;
371  b->right_ = p;
372  if (p->left_) {
373  p->left_->parent_ = p;
374  }
375  } else {
376  p->right_ = b->left_;
377  b->left_ = p;
378  if (p->right_) {
379  p->right_->parent_ = p;
380  }
381  }
382  p->w_ = p->wleft() + p->wright() + 1;
383  if (b->parent_) {
384  if (!b->parent_->check())
385  Printf("b->parent failed end\n");
386  }
387  if (!p->check())
388  Printf("p failed at end\n");
389  if (!b->check())
390  Printf("b failed at end\n");
391  }
392 }
393 
394 TQItem* TQueue::insert(double t, void* data) {
395  PSTART(1)
396  // TQItem* i = new TQItem();
397  TQItem* i = tpool_->alloc();
398  i->data_ = data;
399  insert1(t, i);
400  PSTOP(1)
401  return i;
402 }
403 
404 void TQueue::insert1(double t, TQItem* i) {
405  check("begin insert1");
406 #if FAST_LEAST
407  STAT(ncompare)
408  if (!least_ || t < least_->t_) {
409  least_ = i;
410  }
411 #endif
412  TQItem* p = root_;
413  STAT(ninsert)
414  if (p) {
415  for (;;) {
416  STAT(ncompare)
417  if (t < p->t_) {
418  if (p->left_) {
419  p = p->left_;
420  // if (p->unbalanced()) {
421  // reverse(p);
422  // }
423  } else {
424  p->left_ = i;
425  break;
426  }
427  } else {
428  if (p->right_) {
429  p = p->right_;
430  // if (p->unbalanced()) {
431  // reverse(p);
432  // }
433  } else {
434  p->right_ = i;
435  break;
436  }
437  }
438  }
439  } else {
440  root_ = i;
441  }
442  i->parent_ = p;
443  i->t_ = t;
444  i->w_ = 1;
445  for (p = i->parent_; p; p = p->parent_) {
446  ++p->w_;
447  }
448  for (p = i->parent_; p;) {
449  if (p->unbalanced()) {
450  reverse(p);
451  } else {
452  p = p->parent_;
453  }
454  }
455  check("end insert1");
456 }
457 
459  int balance, dbalance;
460  if (parent_) {
461  balance = parent_->wright() - parent_->wleft();
462  if (parent_->left_ == (TQItem*) this) {
463  if (balance < -(wright() + 1)) {
464  // printf("balance %d to %d\n", balance, balance + 2*(wright()+1));
465  return true;
466  }
467  } else {
468  if (balance > wleft() + 1) {
469  // printf("balance %d to %d\n", balance, balance - 2*(wleft()+1));
470  return true;
471  }
472  }
473  }
474  return false;
475 }
476 
478 #if COLLECT_TQueue_STATISTICS
479  Printf("insertions=%lu moves=%lu fastmoves=%lu removals=%lu calls to least=%lu\n",
480  ninsert,
481  nmove,
482  nfastmove,
483  nrem,
484  nleast);
485  Printf("calls to find=%lu balances=%lu complex removals=%lu\n", nfind, nbal, ncmplxrem);
486  Printf("comparisons=%lu leastsearch=%lu findsearch=%lu\n", ncompare, nleastsrch, nfindsrch);
487 #else
488  Printf("Turn on COLLECT_TQueue_STATISTICS_ in tqueue.h\n");
489 #endif
490 }
491 
492 #endif
#define nil
Definition: enter-scope.h:36
static void deleteitem(TQItem *i)
Definition: bbtqueue.cpp:18
static void prnt(const TQItem *b, int level)
Definition: bbtqueue.cpp:64
static void chk(TQItem *b, int level)
Definition: bbtqueue.cpp:72
Definition: bbtqueue.h:6
int wleft()
Definition: bbtqueue.h:11
virtual ~TQItem()
Definition: bbtqueue.cpp:9
double t_
Definition: bbtqueue.h:23
int w_
Definition: bbtqueue.h:27
bool check()
Definition: bbtqueue.cpp:30
TQItem * right_
Definition: bbtqueue.h:25
bool unbalanced()
Definition: bbtqueue.cpp:458
TQItem()
Definition: bbtqueue.cpp:3
void t_iterate(void(*)(const TQItem *, int), int)
Definition: bbtqueue.cpp:78
TQItem * parent_
Definition: bbtqueue.h:26
TQItem * left_
Definition: bbtqueue.h:24
int wright()
Definition: bbtqueue.h:14
void * data_
Definition: bbtqueue.h:22
unsigned long nbal
Definition: bbtqueue.h:58
void statistics()
Definition: bbtqueue.cpp:477
unsigned long nleastsrch
Definition: bbtqueue.h:59
void remove(TQItem *)
Definition: bbtqueue.cpp:236
void remove1(TQItem *)
Definition: bbtqueue.cpp:245
double least_t()
Definition: bbtqueue.cpp:131
void deleteitem(TQItem *)
Definition: sptbinq.cpp:87
void reverse(TQItem *)
Definition: bbtqueue.cpp:343
TQItem * least()
Definition: bbtqueue.cpp:140
TQItem * root_
Definition: bbtqueue.h:55
void insert1(double t, TQItem *)
Definition: bbtqueue.cpp:404
void check(const char *errmess)
Definition: bbtqueue.cpp:121
TQItemPool * tpool_
Definition: sptbinq.h:153
void move(TQItem *, double tnew)
Definition: bbtqueue.cpp:185
unsigned long nmove
Definition: bbtqueue.h:59
TQItem * least_
Definition: bbtqueue.h:54
TQueue()
Definition: bbtqueue.cpp:90
unsigned long ninsert
Definition: bbtqueue.h:58
void print()
Definition: bbtqueue.cpp:109
unsigned long nrem
Definition: bbtqueue.h:58
unsigned long nfastmove
Definition: bbtqueue.h:59
TQItem * find(double t)
Definition: bbtqueue.cpp:217
unsigned long nfindsrch
Definition: bbtqueue.h:59
unsigned long ncompare
Definition: bbtqueue.h:59
void new_least()
Definition: bbtqueue.cpp:158
unsigned long nleast
Definition: bbtqueue.h:58
unsigned long nfind
Definition: bbtqueue.h:59
unsigned long ncmplxrem
Definition: bbtqueue.h:58
virtual ~TQueue()
Definition: bbtqueue.cpp:103
void forall_callback(void(*)(const TQItem *, int))
Definition: bbtqueue.cpp:115
TQItem * insert(double t, void *data_)
Definition: bbtqueue.cpp:394
void move_least(double tnew)
Definition: bbtqueue.cpp:178
double t
Definition: cvodeobj.cpp:59
void hoc_execerror(const char *, const char *)
Definition: hoc.cpp:754
#define assert(ex)
Definition: hocassrt.h:32
#define i
Definition: md1redef.h:12
#define STAT
Definition: model.h:117
#define Printf
Definition: model.h:237
#define printf
Definition: mwprefix.h:26
size_t p
#define PSTOP(i)
Definition: profile.h:11
#define PSTART(i)
Definition: profile.h:10
#define data
Definition: rbtqueue.cpp:49
static const char * errmess_
Definition: tqueue.cpp:20