DiscretePDF.inc
Go to the documentation of this file.00001
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
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;
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
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);
00296 sibling = n->sibling();
00297 }
00298
00299
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);
00314 sibling->markRed();
00315 sibling->parent->markBlack();
00316 sibling = sibling->parent;
00317 } else if (n==n->parent->right && sibling->leftIsBlack()) {
00318 rotate(sibling->right);
00319 sibling->markRed();
00320 sibling->parent->markBlack();
00321 sibling = sibling->parent;
00322 }
00323
00324
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