Open
Graph Drawing
Framework

 v. 2023.09 (Elderberry)
 

DTree.h
Go to the documentation of this file.
1 
29 #pragma once
30 
32 
33 #include <algorithm> // IWYU pragma: keep
34 
35 namespace ogdf {
36 namespace energybased {
37 namespace dtree {
38 
40 template<typename IntType, int Dim>
41 class DTree {
42 public:
44  static constexpr int MaxNumChildrenPerNode = (1 << Dim);
45 
47  explicit DTree(int numPoints)
48  : m_maxLevel((sizeof(IntType) << 3) + 1), m_numPoints(0), m_rootIndex(-1) {
50  }
51 
53  ~DTree() { deallocate(); }
54 
56  struct Point {
57  IntType x[Dim];
58  };
59 
61  struct MortonEntry {
62  IntType mortonNr[Dim];
63  int ref;
64 
66  bool operator<(const MortonEntry& other) const {
67  return mortonComparerLess<IntType, Dim>(mortonNr, other.mortonNr);
68  }
69 
71  bool operator==(const MortonEntry& other) const {
72  return mortonComparerEqual<IntType, Dim>(mortonNr, other.mortonNr);
73  }
74  };
75 
77  struct Node {
78  // quadtree related stuff
79  int level;
80  int next;
82  int numChilds;
83  int firstPoint;
84  int numPoints;
85  };
86 
88  inline const Node& node(int i) const { return m_nodes[i]; };
89 
91  inline Node& node(int i) { return m_nodes[i]; };
92 
94  inline int numChilds(int i) const { return m_nodes[i].numChilds; };
95 
97  inline int child(int i, int j) const { return m_nodes[i].child[j]; };
98 
100  inline int numPoints(int i) const { return m_nodes[i].numPoints; };
101 
103  inline int point(int i, int j) const { return m_mortonOrder[m_nodes[i].firstPoint + j].ref; };
104 
106  void setPoint(int i, int d, IntType value);
107 
109  inline int numPoints() const { return m_numPoints; };
110 
112  inline int maxNumNodes() const { return m_numPoints * 2; };
113 
115  const Point& point(int i) const { return m_points[i]; }
116 
118  void prepareMortonOrder();
119 
121  void sortMortonNumbers();
122 
124  void prepareNodeLayer();
125 
127  inline void mergeWithNext(int curr);
128 
130  inline void adjustPointInfo(int curr);
131 
133  int linkNodes(int curr, int maxLevel);
134 
136  void linkNodes();
137 
139  void build();
140 
142  int countPoints(int curr) const;
143 
145  int countPoints() const { return countPoints(m_rootIndex); };
146 
148  int rootIndex() const { return m_rootIndex; };
149 
150 private:
152  void allocate(int n);
153 
155  void deallocate();
156 
158  Point* m_points = nullptr;
161  Node* m_nodes = nullptr;
163 };
164 
166 template<typename IntType, int Dim>
168  m_numPoints = n;
169  m_points = new Point[m_numPoints];
170  m_mortonOrder = new MortonEntry[m_numPoints];
171  m_nodes = new Node[m_numPoints * 2];
172 };
173 
175 template<typename IntType, int Dim>
177  delete[] m_points;
178  delete[] m_mortonOrder;
179  delete[] m_nodes;
180 };
181 
182 template<typename IntType, int Dim>
183 void DTree<IntType, Dim>::setPoint(int i, int d, IntType value) {
184  // set i-th point d coord to value
185  m_points[i].x[d] = value;
186 }
187 
189 template<typename IntType, int Dim>
191  // loop over the point order
192  for (int i = 0; i < m_numPoints; i++) {
193  // set i's ref to i
194  m_mortonOrder[i].ref = i;
195 
196  // generate the morton number by interleaving the bits
197  interleaveBits<IntType, Dim>(m_points[i].x, m_mortonOrder[i].mortonNr);
198  }
199 }
200 
202 template<typename IntType, int Dim>
204  // just sort them
205  std::sort(m_mortonOrder, m_mortonOrder + m_numPoints);
206 }
207 
209 template<typename IntType, int Dim>
211  Node* leafLayer = m_nodes;
212  Node* innerLayer = m_nodes + m_numPoints;
213 
214 #if 0
215  int last = 0;
216 #endif
217  for (int i = 0; i < m_numPoints;) {
218  Node& leaf = leafLayer[i];
219  Node& innerNode = innerLayer[i];
220  // i represents the current node on both layers
221  int j = i + 1;
222 
223  // find the next morton number that differs or stop when j is equal to m_numPoints
224  while ((j < m_numPoints) && (m_mortonOrder[i] == m_mortonOrder[j])) {
225  j++;
226  }
227  // j is the index of the next cell (node)
228 
229  // init the node on the leaf layer
230  leaf.firstPoint = i; //< node sits above the first point of the cell
231  leaf.numPoints =
232  j - i; //< number of points with equal morton numbers (number of points in grid cell)
233  leaf.numChilds = 0; //< it's a leaf
234  leaf.level = 0; //< it's a leaf
235  leaf.next = j; //< this leaf hasnt been created yet but we use indices so its ok
236 
237  if (j < m_numPoints) {
238  // Note: the n-th inner node is not needed because we only need n-1 inner nodes to cover n leaves
239  // if we reach the n-1-th inner node, the variable last is set for the last time
240 #if 0
241  last = i;
242 #endif
243  // init the node on the inner node layer
244  innerNode.child[0] = i; //< node sits above the first leaf
245  innerNode.child[1] = j; //< this leaf hasnt been created yet but we use indices so its ok
246  innerNode.numChilds = 2; //< every inner node covers two leaves in the beginning
247  innerNode.level = lowestCommonAncestorLevel<IntType, Dim>(m_mortonOrder[i].mortonNr,
248  m_mortonOrder[j].mortonNr);
249  innerNode.next = m_numPoints + j; // the inner node layer is shifted by n
250  } else {
251  // no next for the last
252  innerLayer[i].next = 0;
253  // this is important to make the recursion stop
254  innerLayer[i].level = m_maxLevel + 1;
255  }
256 
257  // advance to the next cell
258  i = j;
259  };
260  // here we set the successor of the n-1-th inner node to zero to avoid dealing with the n-th inner node
261 #if 0
262  innerLayer[last].next = 0;
263 #endif
264 };
265 
267 template<typename IntType, int Dim>
268 inline void DTree<IntType, Dim>::mergeWithNext(int curr) {
269  int next = node(curr).next;
270  // Cool: since we never touched node(next) before
271  // it is still linked to only two leaves,
272  node(curr).child[node(curr).numChilds++] = node(next).child[1];
273 
274  // thus we don't need this ugly loop:
275  // for (int i=1; i<node(next).numChilds; i++)
276  // node(curr).child[node(curr).numChilds++] = node(next).child[i];
277  node(curr).next = node(next).next;
278 };
279 
280 template<typename IntType, int Dim>
282  // adjust the first such that it matched the first child
283  node(curr).firstPoint = node(node(curr).child[0]).firstPoint;
284 
285  // index of the last child
286  const int lastChild = node(curr).child[node(curr).numChilds - 1];
287 
288  // numPoints is lastPoint + 1 - firstPoint
289  node(curr).numPoints =
290  node(lastChild).firstPoint + node(lastChild).numPoints - node(curr).firstPoint;
291 }
292 
294 template<typename IntType, int Dim>
295 int DTree<IntType, Dim>::linkNodes(int curr, int maxLevel) {
296  // while the subtree is smaller than maxLevel
297  while (node(curr).next && node(node(curr).next).level < maxLevel) {
298  // get next node in the chain
299  int next = node(curr).next;
300  // First case: same level => merge, discard next
301  if (node(curr).level == node(next).level) {
302  mergeWithNext(curr);
303  } else if (node(curr).level < node(next).level) {
304  // Second case: next is higher => become first child
305  // set the first child of next to the current node
306  node(next).child[0] = curr;
307 
308  // adjust the point info of the curr
309  adjustPointInfo(curr);
310 
311  // this is the only case where we advance curr
312  curr = next;
313  } else { // Third case: next is smaller => construct a maximal subtree starting with next
314  int r = linkNodes(next, node(curr).level);
315  node(curr).child[node(curr).numChilds - 1] = r;
316  node(curr).next = node(r).next;
317  };
318  };
319  // adjust the point info of the curr
320  adjustPointInfo(curr);
321 
322  // we are done with this subtree, return the root
323  return curr;
324 };
325 
327 template<typename IntType, int Dim>
329  m_rootIndex = linkNodes(m_numPoints, m_maxLevel);
330 };
331 
333 template<typename IntType, int Dim>
334 int DTree<IntType, Dim>::countPoints(int curr) const {
335  if (m_nodes[curr].numChilds) {
336  int sum = 0;
337  for (int i = 0; i < m_nodes[curr].numChilds; i++) {
338  sum += countPoints(m_nodes[curr].child[i]);
339  };
340 
341  return sum;
342  } else {
343  return m_nodes[curr].numPoints;
344  }
345 };
346 
348 template<typename IntType, int Dim>
350  // prepare the array with the morton numbers
351  prepareMortonOrder();
352 
353  // sort the morton numbers
354  sortMortonNumbers();
355 
356  // prepare the node layer
357  prepareNodeLayer();
358 
360  linkNodes();
361 };
362 
363 }
364 }
365 }
ogdf
The namespace for all OGDF objects.
Definition: multilevelmixer.cpp:39
ogdf::energybased::dtree::DTree::adjustPointInfo
void adjustPointInfo(int curr)
used to update the first and numPoints of inner nodes by linkNodes
Definition: DTree.h:281
ogdf::energybased::dtree::DTree::child
int child(int i, int j) const
returns the index of the j th child of node i
Definition: DTree.h:97
ogdf::energybased::dtree::DTree::mergeWithNext
void mergeWithNext(int curr)
Merges curr with next node in the chain (used by linkNodes)
Definition: DTree.h:268
ogdf::energybased::dtree::DTree::numPoints
int numPoints() const
returns the number of points the quadtree contains
Definition: DTree.h:109
ogdf::energybased::dtree::DTree::MortonEntry
The entry in the sorted order for a point.
Definition: DTree.h:61
ogdf::energybased::dtree::DTree::~DTree
~DTree()
destructor
Definition: DTree.h:53
ogdf::energybased::dtree::DTree::MortonEntry::mortonNr
IntType mortonNr[Dim]
the morton number of the point
Definition: DTree.h:62
ogdf::energybased::dtree::DTree::MortonEntry::operator==
bool operator==(const MortonEntry &other) const
equal comparer for the construction algorithm
Definition: DTree.h:71
ogdf::energybased::dtree::DTree::Node
The node class.
Definition: DTree.h:77
ogdf::energybased::dtree::DTree::prepareMortonOrder
void prepareMortonOrder()
Prepares the morton numbers for sorting.
Definition: DTree.h:190
ogdf::energybased::dtree::DTree::Point::x
IntType x[Dim]
Definition: DTree.h:57
ogdf::energybased::dtree::DTree::m_rootIndex
int m_rootIndex
The index of the root node.
Definition: DTree.h:162
ogdf::energybased::dtree::DTree::m_numPoints
int m_numPoints
Total number of points.
Definition: DTree.h:159
ogdf::energybased::dtree::DTree::countPoints
int countPoints() const
Just for fun: traverse the tree and count the points in the leaves.
Definition: DTree.h:145
ogdf::energybased::dtree::DTree::build
void build()
Does all required steps except the allocate, deallocate, randomPoints.
Definition: DTree.h:349
ogdf::energybased::dtree::DTree::m_maxLevel
int m_maxLevel
Definition: DTree.h:157
ogdf::energybased::dtree::DTree::Node::numChilds
int numChilds
number of children
Definition: DTree.h:82
ogdf::energybased::dtree::DTree::setPoint
void setPoint(int i, int d, IntType value)
sets the point to the given grid coords
Definition: DTree.h:183
ogdf::energybased::dtree::DTree::node
const Node & node(int i) const
Just to access the nodes a little bit easier.
Definition: DTree.h:88
Minisat::Internal::sort
void sort(T *array, int size, LessThan lt)
Definition: Sort.h:57
r
int r[]
Definition: hierarchical-ranking.cpp:13
ogdf::energybased::dtree::DTree::DTree
DTree(int numPoints)
constructor
Definition: DTree.h:47
ogdf::energybased::dtree::DTree::Node::numPoints
int numPoints
the number of points covered by this subtree
Definition: DTree.h:84
ogdf::energybased::dtree::DTree::Node::next
int next
the next node on the same layer (leaf or inner node layer)
Definition: DTree.h:80
ogdf::energybased::dtree::DTree::m_nodes
Node * m_nodes
Memory for all nodes.
Definition: DTree.h:161
ogdf::energybased::dtree::DTree::Point
The point class with integer coords.
Definition: DTree.h:56
ogdf::energybased::dtree::DTree::maxNumNodes
int maxNumNodes() const
returns the maximum number of nodes (and the max index of a node)
Definition: DTree.h:112
utils.h
ogdf::energybased::dtree::DTree::Node::level
int level
the level of the node in a complete quadtree
Definition: DTree.h:79
ogdf::node
NodeElement * node
The type of nodes.
Definition: Graph_d.h:70
ogdf::energybased::dtree::DTree::Node::firstPoint
int firstPoint
the first point in the sorted order covered by this subtree
Definition: DTree.h:83
ogdf::energybased::dtree::DTree::m_points
Point * m_points
The input set.
Definition: DTree.h:158
ogdf::energybased::dtree::DTree::point
const Point & point(int i) const
returns the ith point in the input sequence
Definition: DTree.h:115
ogdf::energybased::dtree::DTree::MortonEntry::ref
int ref
index in the original point order
Definition: DTree.h:63
ogdf::energybased::dtree::DTree::MortonEntry::operator<
bool operator<(const MortonEntry &other) const
less comparator for sort
Definition: DTree.h:66
ogdf::energybased::dtree::DTree::allocate
void allocate(int n)
Allocates memory for n points.
Definition: DTree.h:167
ogdf::energybased::dtree::DTree::linkNodes
void linkNodes()
The Recursive Bottom-Up Construction (recursion start)
Definition: DTree.h:328
ogdf::energybased::dtree::DTree::sortMortonNumbers
void sortMortonNumbers()
Sorts the points by morton number.
Definition: DTree.h:203
ogdf::energybased::dtree::DTree::rootIndex
int rootIndex() const
returns the index of the root node
Definition: DTree.h:148
ogdf::energybased::dtree::DTree::numPoints
int numPoints(int i) const
returns the number of points covered by this subtree
Definition: DTree.h:100
ogdf::energybased::dtree::DTree::m_mortonOrder
MortonEntry * m_mortonOrder
The order to be sorted.
Definition: DTree.h:160
ogdf::energybased::dtree::DTree::point
int point(int i, int j) const
returns the index of the jth point covered by i's subtree.
Definition: DTree.h:103
ogdf::energybased::dtree::DTree::numChilds
int numChilds(int i) const
returns the number of children of node i
Definition: DTree.h:94
ogdf::energybased::dtree::DTree
Implentation of the reduced quadtree for Dim dimensions.
Definition: DTree.h:41
ogdf::energybased::dtree::DTree::MaxNumChildrenPerNode
static constexpr int MaxNumChildrenPerNode
the maximum number of children per node = 2^d
Definition: DTree.h:44
ogdf::energybased::dtree::DTree::deallocate
void deallocate()
Releases memory.
Definition: DTree.h:176
ogdf::energybased::dtree::DTree::node
Node & node(int i)
Just to access the nodes a little bit easier.
Definition: DTree.h:91
ogdf::energybased::dtree::DTree::Node::child
int child[MaxNumChildrenPerNode]
index of the children
Definition: DTree.h:81
ogdf::energybased::dtree::DTree::prepareNodeLayer
void prepareNodeLayer()
Prepares both the leaf and inner node layer.
Definition: DTree.h:210