DiscretePDF.inc

Go to the documentation of this file.
00001 //===- DiscretePDF.inc - --*- C++ -*-===//
00002 
00003 //
00004 
00005 namespace klee {
00006 
00007 template <class T>
00008 class DiscretePDF<T>::Node
00009 {
00010 private:
00011   bool m_mark;
00012 
00013 public:
00014   Node *parent, *left, *right;
00015   T key;
00016   weight_type weight, sumWeights;
00017 
00018 public:
00019   Node(T key_, weight_type weight_, Node *parent_);
00020   ~Node();
00021 
00022   Node *sibling() { return this==parent->left?parent->right:parent->left; }
00023 
00024   void markRed() { m_mark = true; }
00025   void markBlack() { m_mark = false; }
00026   bool isBlack() { return !m_mark; }
00027   bool leftIsBlack() { return !left || left->isBlack(); }
00028   bool rightIsBlack() { return !right || right->isBlack(); }
00029   void setSum() { 
00030     sumWeights = weight;
00031     if (left) sumWeights += left->sumWeights;
00032     if (right) sumWeights += right->sumWeights;
00033   }
00034 };
00035 
00037 
00038 template <class T>
00039 DiscretePDF<T>::Node::Node(T key_, weight_type weight_, Node *parent_) {
00040   m_mark = false;
00041 
00042   key = key_;
00043   weight = weight_;
00044   sumWeights = 0;
00045   left = right = 0;
00046   parent = parent_;
00047 }
00048 
00049 template <class T>
00050 DiscretePDF<T>::Node::~Node() {
00051   if (left) delete left;
00052   if (right) delete right;
00053 }
00054 
00055 //
00056 
00057 template <class T>
00058 DiscretePDF<T>::DiscretePDF() {
00059   m_root = 0;
00060 }
00061 
00062 template <class T>
00063 DiscretePDF<T>::~DiscretePDF() {
00064   if (m_root) delete m_root;
00065 }
00066 
00067 template <class T>
00068 bool DiscretePDF<T>::empty() const {
00069   return m_root == 0;
00070 }
00071 
00072 template <class T>
00073 void DiscretePDF<T>::insert(T item, weight_type weight) {
00074   Node *p=0, *n=m_root;
00075 
00076   while (n) {
00077     if (!n->leftIsBlack() && !n->rightIsBlack())
00078       split(n);
00079 
00080     p = n;
00081     if (n->key==item) {
00082       assert(0 && "insert: argument(item) already in tree");
00083     } else {
00084       n = (item<n->key)?n->left:n->right;
00085     }
00086   }
00087 
00088   n = new Node(item, weight, p);
00089 
00090   if (!p) {
00091     m_root = n;
00092   } else {
00093     if (item<p->key) {
00094       p->left = n;
00095     } else {
00096       p->right = n;
00097     }
00098 
00099     split(n);
00100   }
00101 
00102   propogateSumsUp(n);
00103 }
00104 
00105 template <class T>
00106 void DiscretePDF<T>::remove(T item) {
00107   Node **np = lookup(item, 0);
00108   Node *child, *n = *np;
00109 
00110   if (!n) {
00111     assert(0 && "remove: argument(item) not in tree");
00112   } else {
00113     if (n->left) {
00114       Node **leftMaxp = &n->left;
00115 
00116       while ((*leftMaxp)->right)
00117         leftMaxp = &(*leftMaxp)->right;
00118 
00119       n->key = (*leftMaxp)->key;
00120       n->weight = (*leftMaxp)->weight;
00121 
00122       np = leftMaxp;
00123       n = *np;
00124     }
00125 
00126     // node now has at most one child
00127 
00128     child = n->left?n->left:n->right;
00129     *np = child;
00130 
00131     if (child) {
00132       child->parent = n->parent;
00133 
00134       if (n->isBlack()) {
00135         lengthen(child);
00136       }
00137     }
00138 
00139     propogateSumsUp(n->parent);
00140 
00141     n->left = n->right = 0;
00142     delete n;
00143   }
00144 }
00145 
00146 template <class T>
00147 void DiscretePDF<T>::update(T item, weight_type weight) {
00148   Node *n = *lookup(item, 0);
00149 
00150   if (!n) {
00151     assert(0 && "update: argument(item) not in tree");
00152   } else {
00153     n->weight = weight;
00154     propogateSumsUp(n);
00155   }
00156 }
00157 
00158 template <class T>
00159 T DiscretePDF<T>::choose(double p) {
00160   if (p<0.0 || p>=1.0) {
00161     assert(0 && "choose: argument(p) outside valid range");
00162   } else if (!m_root) {
00163     assert(0 && "choose: choose() called on empty tree");
00164   } else {
00165     weight_type w = (weight_type) (m_root->sumWeights * p);
00166     Node *n = m_root;
00167 
00168     while (1) {
00169       if (n->left) {
00170         if (w<n->left->sumWeights) {
00171           n = n->left;
00172           continue;
00173         } else {
00174           w -= n->left->sumWeights;
00175         }
00176       }
00177       if (w<n->weight || !n->right) {
00178         break; // !n->right condition shouldn't be necessary, just sanity check
00179       }
00180       w -= n->weight;
00181       n = n->right;
00182     }
00183 
00184     return n->key;
00185   }
00186 }
00187 
00188 template <class T>
00189 bool DiscretePDF<T>::inTree(T item) {
00190   Node *n = *lookup(item, 0);
00191 
00192   return !!n;
00193 }
00194 
00195 template <class T>
00196 typename DiscretePDF<T>::weight_type DiscretePDF<T>::getWeight(T item) {
00197   Node *n = *lookup(item, 0);
00198   assert(n);
00199   return n->weight;
00200 }
00201 
00202 //
00203 
00204 template <class T>
00205 typename DiscretePDF<T>::Node **
00206 DiscretePDF<T>::lookup(T item, Node **parent_out) {
00207   Node *n, *p=0, **np=&m_root;
00208 
00209   while ((n = *np)) {
00210     if (n->key==item) {
00211       break;
00212     } else {
00213       p = n;
00214       if (item<n->key) {
00215         np = &n->left;
00216       } else {
00217         np = &n->right;
00218       }
00219     }
00220   }
00221 
00222   if (parent_out)
00223     *parent_out = p;
00224   return np;
00225 }
00226 
00227 template <class T>
00228 void DiscretePDF<T>::split(Node *n) {
00229   if (n->left) n->left->markBlack();
00230   if (n->right) n->right->markBlack();
00231 
00232   if (n->parent) {
00233     Node *p = n->parent;
00234 
00235     n->markRed();
00236 
00237     if (!p->isBlack()) {
00238       p->parent->markRed();
00239 
00240       // not same direction
00241       if (!((n==p->left && p==p->parent->left) || 
00242             (n==p->right && p==p->parent->right))) {
00243         rotate(n);
00244         p = n;
00245       }
00246 
00247       rotate(p);
00248       p->markBlack();
00249     }
00250   }
00251 }
00252 
00253 template <class T>
00254 void DiscretePDF<T>::rotate(Node *n) {
00255   Node *p=n->parent, *pp=p->parent;
00256 
00257   n->parent = pp;
00258   p->parent = n;
00259 
00260   if (n==p->left) {
00261     p->left = n->right;
00262     n->right = p;
00263     if (p->left) p->left->parent = p;
00264   } else {
00265     p->right = n->left;
00266     n->left = p;
00267     if (p->right) p->right->parent = p;
00268   }
00269 
00270   n->setSum();
00271   p->setSum();
00272         
00273   if (!pp) {
00274     m_root = n;
00275   } else {
00276     if (p==pp->left) {
00277       pp->left = n;
00278     } else {
00279       pp->right = n;
00280     }
00281   }
00282 }
00283 
00284 template <class T>
00285 void DiscretePDF<T>::lengthen(Node *n) {
00286   if (!n->isBlack()) {
00287     n->markBlack();
00288   } else if (n->parent) {
00289     Node *sibling = n->sibling();
00290 
00291     if (sibling && !sibling->isBlack()) {
00292       n->parent->markRed();
00293       sibling->markBlack();
00294 
00295       rotate(sibling); // node sibling is now old sibling child, must be black
00296       sibling = n->sibling();
00297     }
00298 
00299     // sibling is black
00300 
00301     if (!sibling) {
00302       lengthen(n->parent);
00303     } else if (sibling->leftIsBlack() && sibling->rightIsBlack()) {
00304       if (n->parent->isBlack()) {
00305         sibling->markRed();
00306         lengthen(n->parent);
00307       } else {
00308         sibling->markRed();
00309         n->parent->markBlack();
00310       }
00311     } else {
00312       if (n==n->parent->left && sibling->rightIsBlack()) {
00313         rotate(sibling->left); // sibling->left must be red
00314         sibling->markRed();
00315         sibling->parent->markBlack();
00316         sibling = sibling->parent;
00317       } else if (n==n->parent->right && sibling->leftIsBlack()) {
00318         rotate(sibling->right); // sibling->right must be red
00319         sibling->markRed();
00320         sibling->parent->markBlack();
00321         sibling = sibling->parent;
00322       }
00323 
00324       // sibling is black, and sibling's far child is red
00325 
00326       rotate(sibling);
00327       if (!n->parent->isBlack()) 
00328         sibling->markRed();
00329       sibling->left->markBlack();
00330       sibling->right->markBlack();
00331     }
00332   }
00333 }
00334 
00335 template <class T>
00336 void DiscretePDF<T>::propogateSumsUp(Node *n) {
00337   for (; n; n=n->parent)
00338     n->setSum();
00339 }
00340 
00341 }
00342 

Generated on Fri Jun 5 03:31:31 2009 for klee by  doxygen 1.5.8