votca 2024.1-dev
Loading...
Searching...
No Matches
huffmantree.h
Go to the documentation of this file.
1/*
2 * Copyright 2009-2020 The VOTCA Development Team (http://www.votca.org)
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 *
15 */
16#pragma once
17#ifndef VOTCA_XTP_HUFFMANTREE_H
18#define VOTCA_XTP_HUFFMANTREE_H
19
20// Standard includes
21#include <cstdlib>
22#include <list>
23#include <queue>
24#include <vector>
25
26namespace votca {
27namespace xtp {
28
29template <class T>
31
32 public:
33 void makeTree() {
34 if (!events) {
35 throw std::runtime_error(
36 "Error in Huffmantree::makeTree : Pointer to Events not set!");
37 }
38
39 // queue of the nodes, sorted by probability
40 auto compare = [](huffmanNode<T> *n1, huffmanNode<T> *n2) {
41 return n1->probability > n2->probability;
42 };
43
44 // priority queues, because the algorithm always needs the element with the
45 // smallest probability. Also, it keep adding nodes to it, so it would we
46 // very inefficient to sort it in every iteration.
47 std::priority_queue<huffmanNode<T> *, std::vector<huffmanNode<T> *>,
48 decltype(compare)>
49 queue(compare);
50
51 htree = std::vector<huffmanNode<T>>(
52 events->size() % 2 ? events->size() : events->size() - 1);
53
54 auto comp2 = [](T *e1, T *e2) { return e1->getValue() > e2->getValue(); };
55 std::priority_queue<T *, std::vector<T *>, decltype(comp2)> eventQueue(
56 comp2);
57 sum_of_values = 0.0;
58
59 Index firstEmptyFieldIndex = 0;
60 for (T &e : *events) {
61 eventQueue.push(&e);
62 sum_of_values += e.getValue();
63 }
64 while (eventQueue.size() > 1) {
65 htree[firstEmptyFieldIndex].isOnLastLevel = true;
66 htree[firstEmptyFieldIndex].leftLeaf = eventQueue.top();
67 eventQueue.pop();
68 htree[firstEmptyFieldIndex].rightLeaf = eventQueue.top();
69 eventQueue.pop();
70 htree[firstEmptyFieldIndex].probability =
71 (htree[firstEmptyFieldIndex].leftLeaf->getValue() +
72 htree[firstEmptyFieldIndex].rightLeaf->getValue()) /
74 queue.push(&(htree[firstEmptyFieldIndex]));
75 firstEmptyFieldIndex++;
76 }
77 if (!eventQueue.empty()) {
78 htree[firstEmptyFieldIndex].isOnLastLevel = true;
79 htree[firstEmptyFieldIndex].rightLeaf = eventQueue.top();
80 htree[firstEmptyFieldIndex].leftLeaf = eventQueue.top();
81 htree[firstEmptyFieldIndex].probability =
82 htree[firstEmptyFieldIndex].leftLeaf->getValue() / sum_of_values;
83 queue.push(&(htree[firstEmptyFieldIndex]));
84 firstEmptyFieldIndex++;
85 }
86
87 // now connect the hnodes, making a new one for every connection:
88 // always take the two nodes with the smallest probability and "combine"
89 // them, repeat, until just one node (the root) is left.
92 while (queue.size() > 1) {
93 h1 = queue.top();
94 queue.pop();
95 h2 = queue.top();
96 queue.pop();
97 htree[firstEmptyFieldIndex].probability =
98 h1->probability + h2->probability;
99 htree[firstEmptyFieldIndex].leftChild = h1;
100 htree[firstEmptyFieldIndex].rightChild = h2;
101 queue.push(&(htree[firstEmptyFieldIndex]));
102 firstEmptyFieldIndex++;
103 }
104 // reorganize the probabilities: in every node, add the probability of one
105 // subtree ("small") to all nodes of the other subtree.
108 treeIsMade = true;
109 }
110
111 T *findHoppingDestination(double p) const {
112 if (!treeIsMade) {
113 throw std::runtime_error(
114 "Tried to find Hopping Destination without initializing the "
115 "Huffmantree first!");
116 }
117 const huffmanNode<T> *node = &htree.back();
118 while (!node->isOnLastLevel) {
119 if (p > node->probability) {
120 node = node->leftChild;
121 } else {
122 node = node->rightChild;
123 }
124 }
125 return (p > node->probability ? node->leftLeaf : node->rightLeaf);
126 }
127
128 void setEvents(std::vector<T> *v) { this->events = v; }
129
130 private:
131 template <class S>
132 struct huffmanNode {
133 // huffmanNode * for the inner nodes, T * for the nodes on the last level
134 // before the leafs (The T themselves represent the "leaf" level)
140 bool isOnLastLevel = false;
141 };
142
144 double add) {
145 // for each node, adds the probability of the right childnode to the left
146 // childnode and every node under it. if the Tree would look like this (with
147 // the Numbers representing the probability of every node) before calling
148 // this function
149
150 // 1.0
151 // ____||____
152 // | |
153 // 0.4 0.6
154 // _||_ _||_
155 // | | | |
156 // 0.25 0.15 0.35 0.25
157 // _||_
158 // | |
159 // 0.1 0.05
160 // then it would look like this after calling it
161 // 1.0
162 // ____||____
163 // | |
164 // 1.0 0.6
165 // _||_ _||_
166 // | | | |
167 // 1.0 0.75 0.6 0.25
168 // _||_
169 // | |
170 // 0.75 0.65
171 // now the tree could be traversed with "while (!n.isLeaf())
172 // n=p>n.right.p?n.left:n.right" so in the function
173 // moveProbabilitiesFromRightSubtreesOneLevelUp the numbers are moved one
174 // level up to call n.p instead of n.right.p
175
176 // adds "add" to the probability, then calls itself recursively.
177 // this calculates the probabilities needed to traverse the tree quickly
178 n->probability += add;
179 // if leftId=-1 (=> node is leaf), returns
180 if (n->isOnLastLevel) {
181 return;
182 }
183
185 n->leftChild, add + n->rightChild->probability);
187 }
188
190 // moves the Probabilities on the right subtrees one level up.
191 // if the Tree would look like this (with the Numbers representing the
192 // probability of every node) before calling this function
193 // 1.0
194 // ____||____
195 // | |
196 // 1.0 0.6
197 // _||_ _||_
198 // | | | |
199 // 1.0 0.75 0.6 0.25
200 // _||_
201 // | |
202 // 0.75 0.65
203 // then it would look like this after calling it
204 // 0.
205 // ____||____
206 // | |
207 // 0.75 0.25
208 // _||_ _||_
209 // | | | |
210 // 1.0 0.65 0.6 0.25
211 // _||_
212 // | |
213 // 0.75 0.65
214 // note, that now the probabilities on the leaf level are not needed anymore
215 // to traverse the tree; the algorithm now is "while (!n.isLeaf())
216 // n=p>n.p?n.left:n.right"
217 if (n->isOnLastLevel) {
218 n->probability -= n->leftLeaf->getValue() / sum_of_values;
219 } else {
223 }
224 }
225
226 std::vector<huffmanNode<T>> htree;
227 bool treeIsMade = false;
228 double sum_of_values = 0.0;
229 std::vector<T> *events = nullptr;
230};
231
232} // namespace xtp
233} // namespace votca
234#endif // VOTCA_XTP_HUFFMANTREE_H
void moveProbabilitiesFromRightSubtreesOneLevelUp(huffmanNode< T > *n)
T * findHoppingDestination(double p) const
void addProbabilityFromRightSubtreeToLeftSubtree(huffmanNode< T > *n, double add)
std::vector< huffmanNode< T > > htree
std::vector< T > * events
void setEvents(std::vector< T > *v)
base class for all analysis tools
Definition basebead.h:33
Eigen::Index Index
Definition types.h:26