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