Loading [MathJax]/extensions/tex2jax.js
CoreNEURON
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
tqueue.cpp
Go to the documentation of this file.
1 /*
2 # =============================================================================
3 # Copyright (c) 2016 - 2021 Blue Brain Project/EPFL
4 #
5 # See top-level LICENSE file for details.
6 # =============================================================================.
7 */
8 
9 #include <cstdio>
10 #include <cstdlib>
11 #include <cstring>
12 #include <cstdarg>
13 
16 
17 namespace coreneuron {
18 // splay tree + bin queue limited to fixed step method
19 // for event-sets or priority queues
20 // this starts from the sptqueue.cpp file and adds a bin queue
21 
22 /* Derived from David Brower's c translation of pascal code by
23 Douglas Jones.
24 */
25 /* The original c code is included from this file but note that instead
26 of struct _spblk, we are really using TQItem
27 */
28 
30  nbin_ = 1000;
31  bins_ = new TQItem*[nbin_];
32  for (int i = 0; i < nbin_; ++i) {
33  bins_[i] = 0;
34  }
35  qpt_ = 0;
36  tt_ = 0.;
37 }
38 
40  for (int i = 0; i < nbin_; ++i) {
41  assert(!bins_[i]);
42  }
43  delete[] bins_;
44  vec_bins.clear();
45 }
46 
47 void BinQ::resize(int size) {
48  // printf("BinQ::resize from %d to %d\n", nbin_, size);
49  assert(size >= nbin_);
50  TQItem** bins = new TQItem*[size];
51  for (int i = nbin_; i < size; ++i) {
52  bins[i] = 0;
53  }
54  for (int i = 0, j = qpt_; i < nbin_; ++i, ++j) {
55  if (j >= nbin_) {
56  j = 0;
57  }
58  bins[i] = bins_[j];
59  for (auto q = bins[i]; q; q = q->left_) {
60  q->cnt_ = i;
61  }
62  }
63  delete[] bins_;
64  bins_ = bins;
65  nbin_ = size;
66  qpt_ = 0;
67 }
68 void BinQ::enqueue(double td, TQItem* q) {
69  int idt = (int) ((td - tt_) * rev_dt + 1.e-10);
70  assert(idt >= 0);
71  if (idt >= nbin_) {
72  resize(idt + 1000);
73  }
74  // assert (idt < nbin_);
75  idt += qpt_;
76  if (idt >= nbin_) {
77  idt -= nbin_;
78  }
79  // printf("enqueue: idt=%d qpt=%d nbin_=%d\n", idt, qpt_, nbin_);
80  assert(idt < nbin_);
81  q->cnt_ = idt; // only for iteration
82  q->left_ = bins_[idt];
83  bins_[idt] = q;
84 }
86  TQItem* q = bins_[qpt_];
87  if (q) {
88  bins_[qpt_] = q->left_;
89  }
90  return q;
91 }
92 
94  for (int i = 0; i < nbin_; ++i) {
95  if (bins_[i]) {
96  return bins_[i];
97  }
98  }
99  return 0;
100 }
102  if (q->left_) {
103  return q->left_;
104  }
105  for (int i = q->cnt_ + 1; i < nbin_; ++i) {
106  if (bins_[i]) {
107  return bins_[i];
108  }
109  }
110  return 0;
111 }
112 
114  TQItem* q1 = bins_[q->cnt_];
115  if (q1 == q) {
116  bins_[q->cnt_] = q->left_;
117  return;
118  }
119  for (TQItem* q2 = q1->left_; q2; q1 = q2, q2 = q2->left_) {
120  if (q2 == q) {
121  q1->left_ = q->left_;
122  return;
123  }
124  }
125 }
126 
127 //#include "coreneuron/nrniv/sptree.h"
128 
129 /*
130  * The following code implements the basic operations on
131  * an event-set or priority-queue implemented using splay trees:
132  *
133 Hines changed to void spinit(SPTREE**) for use with TQueue.
134  * SPTREE *spinit( compare ) Make a new tree
135  * SPBLK *spenq( n, q ) Insert n in q after all equal keys.
136  * SPBLK *spdeq( np ) Return first key under *np, removing it.
137  * void splay( n, q ) n (already in q) becomes the root.
138  * int n = sphead( q ) n is the head item in q (not removed).
139  * spdelete( n, q ) n is removed from q.
140  *
141  * In the above, n points to an SPBLK type, while q points to an
142  * SPTREE.
143  *
144  * The implementation used here is based on the implementation
145  * which was used in the tests of splay trees reported in:
146  *
147  * An Empirical Comparison of Priority-Queue and Event-Set Implementations,
148  * by Douglas W. Jones, Comm. ACM 29, 4 (Apr. 1986) 300-311.
149  *
150  * The changes made include the addition of the enqprior
151  * operation and the addition of up-links to allow for the splay
152  * operation. The basic splay tree algorithms were originally
153  * presented in:
154  *
155  * Self Adjusting Binary Trees,
156  * by D. D. Sleator and R. E. Tarjan,
157  * Proc. ACM SIGACT Symposium on Theory
158  * of Computing (Boston, Apr 1983) 235-245.
159  *
160  * The enq and enqprior routines use variations on the
161  * top-down splay operation, while the splay routine is bottom-up.
162  * All are coded for speed.
163  *
164  * Written by:
165  * Douglas W. Jones
166  *
167  * Translated to C by:
168  * David Brower, daveb@rtech.uucp
169  *
170  * Thu Oct 6 12:11:33 PDT 1988 (daveb) Fixed spdeq, which was broken
171  * handling one-node trees. I botched the pascal translation of
172  * a VAR parameter.
173  */
174 
175 /*----------------
176  *
177  * spinit() -- initialize an empty splay tree
178  *
179  */
180 void spinit(SPTREE* q) {
181  q->enqcmps = 0;
182  q->root = nullptr;
183 }
184 
185 /*----------------
186  *
187  * spenq() -- insert item in a tree.
188  *
189  * put n in q after all other nodes with the same key; when this is
190  * done, n will be the root of the splay tree representing q, all nodes
191  * in q with keys less than or equal to that of n will be in the
192  * left subtree, all with greater keys will be in the right subtree;
193  * the tree is split into these subtrees from the top down, with rotations
194  * performed along the way to shorten the left branch of the right subtree
195  * and the right branch of the left subtree
196  */
198  SPBLK* left; /* the rightmost node in the left tree */
199  SPBLK* right; /* the leftmost node in the right tree */
200  SPBLK* next; /* the root of the unsplit part */
201  SPBLK* temp;
202 
203  double key;
204 
205  n->uplink = nullptr;
206  next = q->root;
207  q->root = n;
208  if (next == nullptr) /* trivial enq */
209  {
210  n->leftlink = nullptr;
211  n->rightlink = nullptr;
212  } else /* difficult enq */
213  {
214  key = n->key;
215  left = n;
216  right = n;
217 
218  /* n's left and right children will hold the right and left
219  splayed trees resulting from splitting on n->key;
220  note that the children will be reversed! */
221 
222  q->enqcmps++;
223  if (STRCMP(next->key, key) > 0)
224  goto two;
225 
226  one: /* assert next->key <= key */
227 
228  do /* walk to the right in the left tree */
229  {
230  temp = next->rightlink;
231  if (temp == nullptr) {
232  left->rightlink = next;
233  next->uplink = left;
234  right->leftlink = nullptr;
235  goto done; /* job done, entire tree split */
236  }
237 
238  q->enqcmps++;
239  if (STRCMP(temp->key, key) > 0) {
240  left->rightlink = next;
241  next->uplink = left;
242  left = next;
243  next = temp;
244  goto two; /* change sides */
245  }
246 
247  next->rightlink = temp->leftlink;
248  if (temp->leftlink != nullptr)
249  temp->leftlink->uplink = next;
250  left->rightlink = temp;
251  temp->uplink = left;
252  temp->leftlink = next;
253  next->uplink = temp;
254  left = temp;
255  next = temp->rightlink;
256  if (next == nullptr) {
257  right->leftlink = nullptr;
258  goto done; /* job done, entire tree split */
259  }
260 
261  q->enqcmps++;
262 
263  } while (STRCMP(next->key, key) <= 0); /* change sides */
264 
265  two: /* assert next->key > key */
266 
267  do /* walk to the left in the right tree */
268  {
269  temp = next->leftlink;
270  if (temp == nullptr) {
271  right->leftlink = next;
272  next->uplink = right;
273  left->rightlink = nullptr;
274  goto done; /* job done, entire tree split */
275  }
276 
277  q->enqcmps++;
278  if (STRCMP(temp->key, key) <= 0) {
279  right->leftlink = next;
280  next->uplink = right;
281  right = next;
282  next = temp;
283  goto one; /* change sides */
284  }
285  next->leftlink = temp->rightlink;
286  if (temp->rightlink != nullptr)
287  temp->rightlink->uplink = next;
288  right->leftlink = temp;
289  temp->uplink = right;
290  temp->rightlink = next;
291  next->uplink = temp;
292  right = temp;
293  next = temp->leftlink;
294  if (next == nullptr) {
295  left->rightlink = nullptr;
296  goto done; /* job done, entire tree split */
297  }
298 
299  q->enqcmps++;
300 
301  } while (STRCMP(next->key, key) > 0); /* change sides */
302 
303  goto one;
304 
305  done: /* split is done, branches of n need reversal */
306 
307  temp = n->leftlink;
308  n->leftlink = n->rightlink;
309  n->rightlink = temp;
310  }
311 
312  return (n);
313 
314 } /* spenq */
315 
316 /*----------------
317  *
318  * spdeq() -- return and remove head node from a subtree.
319  *
320  * remove and return the head node from the node set; this deletes
321  * (and returns) the leftmost node from q, replacing it with its right
322  * subtree (if there is one); on the way to the leftmost node, rotations
323  * are performed to shorten the left branch of the tree
324  */
325 SPBLK* spdeq(SPBLK** np) /* pointer to a node pointer */
326 
327 {
328  SPBLK* deq; /* one to return */
329  SPBLK* next; /* the next thing to deal with */
330  SPBLK* left; /* the left child of next */
331  SPBLK* farleft; /* the left child of left */
332  SPBLK* farfarleft; /* the left child of farleft */
333 
334  if (np == nullptr || *np == nullptr) {
335  deq = nullptr;
336  } else {
337  next = *np;
338  left = next->leftlink;
339  if (left == nullptr) {
340  deq = next;
341  *np = next->rightlink;
342 
343  if (*np != nullptr)
344  (*np)->uplink = nullptr;
345 
346  } else
347  for (;;) /* left is not null */
348  {
349  /* next is not it, left is not nullptr, might be it */
350  farleft = left->leftlink;
351  if (farleft == nullptr) {
352  deq = left;
353  next->leftlink = left->rightlink;
354  if (left->rightlink != nullptr)
355  left->rightlink->uplink = next;
356  break;
357  }
358 
359  /* next, left are not it, farleft is not nullptr, might be it */
360  farfarleft = farleft->leftlink;
361  if (farfarleft == nullptr) {
362  deq = farleft;
363  left->leftlink = farleft->rightlink;
364  if (farleft->rightlink != nullptr)
365  farleft->rightlink->uplink = left;
366  break;
367  }
368 
369  /* next, left, farleft are not it, rotate */
370  next->leftlink = farleft;
371  farleft->uplink = next;
372  left->leftlink = farleft->rightlink;
373  if (farleft->rightlink != nullptr)
374  farleft->rightlink->uplink = left;
375  farleft->rightlink = left;
376  left->uplink = farleft;
377  next = farleft;
378  left = farfarleft;
379  }
380  }
381 
382  return (deq);
383 
384 } /* spdeq */
385 
386 /*----------------
387  *
388  * splay() -- reorganize the tree.
389  *
390  * the tree is reorganized so that n is the root of the
391  * splay tree representing q; results are unpredictable if n is not
392  * in q to start with; q is split from n up to the old root, with all
393  * nodes to the left of n ending up in the left subtree, and all nodes
394  * to the right of n ending up in the right subtree; the left branch of
395  * the right subtree and the right branch of the left subtree are
396  * shortened in the process
397  *
398  * this code assumes that n is not nullptr and is in q; it can sometimes
399  * detect n not in q and complain
400  */
401 
402 void splay(SPBLK* n, SPTREE* q) {
403  SPBLK* up; /* points to the node being dealt with */
404  SPBLK* prev; /* a descendent of up, already dealt with */
405  SPBLK* upup; /* the parent of up */
406  SPBLK* upupup; /* the grandparent of up */
407  SPBLK* left; /* the top of left subtree being built */
408  SPBLK* right; /* the top of right subtree being built */
409 
410  left = n->leftlink;
411  right = n->rightlink;
412  prev = n;
413  up = prev->uplink;
414 
415  while (up != nullptr) {
416  /* walk up the tree towards the root, splaying all to the left of
417  n into the left subtree, all to right into the right subtree */
418 
419  upup = up->uplink;
420  if (up->leftlink == prev) /* up is to the right of n */
421  {
422  if (upup != nullptr && upup->leftlink == up) /* rotate */
423  {
424  upupup = upup->uplink;
425  upup->leftlink = up->rightlink;
426  if (upup->leftlink != nullptr)
427  upup->leftlink->uplink = upup;
428  up->rightlink = upup;
429  upup->uplink = up;
430  if (upupup == nullptr)
431  q->root = up;
432  else if (upupup->leftlink == upup)
433  upupup->leftlink = up;
434  else
435  upupup->rightlink = up;
436  up->uplink = upupup;
437  upup = upupup;
438  }
439  up->leftlink = right;
440  if (right != nullptr)
441  right->uplink = up;
442  right = up;
443 
444  } else /* up is to the left of n */
445  {
446  if (upup != nullptr && upup->rightlink == up) /* rotate */
447  {
448  upupup = upup->uplink;
449  upup->rightlink = up->leftlink;
450  if (upup->rightlink != nullptr)
451  upup->rightlink->uplink = upup;
452  up->leftlink = upup;
453  upup->uplink = up;
454  if (upupup == nullptr)
455  q->root = up;
456  else if (upupup->rightlink == upup)
457  upupup->rightlink = up;
458  else
459  upupup->leftlink = up;
460  up->uplink = upupup;
461  upup = upupup;
462  }
463  up->rightlink = left;
464  if (left != nullptr)
465  left->uplink = up;
466  left = up;
467  }
468  prev = up;
469  up = upup;
470  }
471 
472 #ifdef DEBUG
473  if (q->root != prev) {
474  /* fprintf(stderr, " *** bug in splay: n not in q *** " ); */
475  abort();
476  }
477 #endif
478 
479  n->leftlink = left;
480  n->rightlink = right;
481  if (left != nullptr)
482  left->uplink = n;
483  if (right != nullptr)
484  right->uplink = n;
485  q->root = n;
486  n->uplink = nullptr;
487 
488 } /* splay */
489 
490 /*----------------
491  *
492  * sphead() -- return the "lowest" element in the tree.
493  *
494  * returns a reference to the head event in the event-set q,
495  * represented as a splay tree; q->root ends up pointing to the head
496  * event, and the old left branch of q is shortened, as if q had
497  * been splayed about the head element; this is done by dequeueing
498  * the head and then making the resulting queue the right son of
499  * the head returned by spdeq; an alternative is provided which
500  * avoids splaying but just searches for and returns a pointer to
501  * the bottom of the left branch
502  */
504  SPBLK* x;
505 
506  /* splay version, good amortized bound */
507  x = spdeq(&q->root);
508  if (x != nullptr) {
509  x->rightlink = q->root;
510  x->leftlink = nullptr;
511  x->uplink = nullptr;
512  if (q->root != nullptr)
513  q->root->uplink = x;
514  }
515  q->root = x;
516 
517  /* alternative version, bad amortized bound,
518  but faster on the average */
519 
520  return (x);
521 
522 } /* sphead */
523 
524 /*----------------
525  *
526  * spdelete() -- Delete node from a tree.
527  *
528  * n is deleted from q; the resulting splay tree has been splayed
529  * around its new root, which is the successor of n
530  *
531  */
532 void spdelete(SPBLK* n, SPTREE* q) {
533  SPBLK* x;
534 
535  splay(n, q);
536  x = spdeq(&q->root->rightlink);
537  if (x == nullptr) /* empty right subtree */
538  {
539  q->root = q->root->leftlink;
540  if (q->root)
541  q->root->uplink = nullptr;
542  } else /* non-empty right subtree */
543  {
544  x->uplink = nullptr;
545  x->leftlink = q->root->leftlink;
546  x->rightlink = q->root->rightlink;
547  if (x->leftlink != nullptr)
548  x->leftlink->uplink = x;
549  if (x->rightlink != nullptr)
550  x->rightlink->uplink = x;
551  q->root = x;
552  }
553 
554 } /* spdelete */
555 } // namespace coreneuron
coreneuron::BinQ::enqueue
void enqueue(double tt, TQItem *)
Definition: tqueue.cpp:68
coreneuron::rev_dt
int rev_dt
Definition: register_mech.cpp:23
coreneuron::BinQ::next
TQItem * next(TQItem *)
Definition: tqueue.cpp:101
coreneuron::TQItem
Definition: tqueue.hpp:69
tqueue.hpp
coreneuron::coreneuron::one
@ one
Definition: nrn_setup.hpp:53
STRCMP
#define STRCMP(a, b)
Definition: tqueue.hpp:37
coreneuron::BinQ::BinQ
BinQ()
Definition: tqueue.cpp:29
coreneuron::BinQ::nbin_
int nbin_
Definition: tqueue.hpp:115
coreneuron::SPTREE::enqcmps
int enqcmps
Definition: tqueue.hpp:51
coreneuron::coreneuron::two
@ two
Definition: nrn_setup.hpp:53
coreneuron
THIS FILE IS AUTO GENERATED DONT MODIFY IT.
Definition: corenrn_parameters.cpp:12
coreneuron::i
int i
Definition: cellorder.cpp:485
coreneuron::BinQ::vec_bins
std::vector< std::vector< TQItem * > > vec_bins
Definition: tqueue.hpp:117
coreneuron::SPTREE
Definition: tqueue.hpp:47
coreneuron::spenq
SPBLK * spenq(SPBLK *n, SPTREE *q)
Definition: tqueue.cpp:197
coreneuron::sphead
SPBLK * sphead(SPTREE *q)
Definition: tqueue.cpp:503
key
#define key
Definition: tqueue.hpp:45
coreneuron::spdelete
void spdelete(SPBLK *n, SPTREE *q)
Definition: tqueue.cpp:532
coreneuron::spdeq
SPBLK * spdeq(SPBLK **np)
Definition: tqueue.cpp:325
coreneuron::TQItem::cnt_
int cnt_
Definition: tqueue.hpp:76
coreneuron::BinQ::bins_
TQItem ** bins_
Definition: tqueue.hpp:116
coreneuron::BinQ::remove
void remove(TQItem *)
Definition: tqueue.cpp:113
coreneuron::spinit
void spinit(SPTREE *q)
Definition: tqueue.cpp:180
SPBLK
#define SPBLK
Definition: tqueue.hpp:40
coreneuron::splay
void splay(SPBLK *n, SPTREE *q)
Definition: tqueue.cpp:402
multicore.hpp
coreneuron::TQItem::left_
TQItem * left_
Definition: tqueue.hpp:73
coreneuron::BinQ::qpt_
int qpt_
Definition: tqueue.hpp:115
coreneuron::np
static int np
Definition: mpispike.cpp:25
coreneuron::SPTREE::root
SPBLK * root
Definition: tqueue.hpp:48
coreneuron::BinQ::dequeue
TQItem * dequeue()
Definition: tqueue.cpp:85
coreneuron::BinQ::first
TQItem * first()
Definition: tqueue.cpp:93
coreneuron::BinQ::resize
void resize(int)
Definition: tqueue.cpp:47
coreneuron::BinQ::~BinQ
~BinQ()
Definition: tqueue.cpp:39
coreneuron::BinQ::tt_
double tt_
Definition: tqueue.hpp:114