Open
Graph Drawing
Framework

 v. 2023.09 (Elderberry)
 

DTreeWSPD.h
Go to the documentation of this file.
1 
29 #pragma once
30 
31 #include <ogdf/basic/basic.h>
33 
34 #include <algorithm>
35 #include <utility>
36 
37 namespace ogdf {
38 namespace energybased {
39 namespace dtree {
40 
41 class IWSPD {
42 public:
44  virtual void onWellSeparatedPair(int aIndex, int bIndex) = 0;
45 };
46 
47 template<int Dim>
48 class DTreeWSPD {
49 public:
50  using IntType = unsigned int;
52 
54  explicit DTreeWSPD(int numPoints);
55 
57  ~DTreeWSPD();
58 
60  struct NodeData {
62  double x[Dim];
63 
65  double min_x[Dim];
66 
68  double max_x[Dim];
69 
71  double radius_sq;
72  };
73 
75  struct PointData {
77  double x[Dim];
78  };
79 
81  void update();
82 
84  const Tree& tree() const { return *m_pTree; };
85 
87  const NodeData& node(int i) const { return m_nodeData[i]; };
88 
90  void setPoint(int i, int d, double coord);
91 
93  const PointData& point(int i) const { return m_pointData[i]; };
94 
95  // temp function for
96  void computeWSPD(IWSPD* m_pIWSPD);
97 
99  double separationFactor() const { return m_wspdSeparationFactor; };
100 
103 
104 protected:
105  IWSPD* m_pIWSPD = nullptr;
106 
108  NodeData& node(int i) { return m_nodeData[i]; };
109 
111  void updateBoundingBox();
112 
114  void updateTreeGridPoints();
115 
117  void updateTreeNodeGeometry();
118 
120  void updateTreeNodeGeometry(int curr);
121 
123  void wspdRecursive(int a);
124 
126  void wspdRecursive(int a, int b);
127 
129  bool areWellSeparated(int a, int b) const;
130 
132  void allocate();
133 
135  void deallocate();
136 
139 
142 
145 
147  Tree* m_pTree = nullptr;
148 
150  NodeData* m_nodeData = nullptr;
151 
153  PointData* m_pointData = nullptr;
154 
156  double m_bboxMin[Dim];
157 
159  double m_bboxMax[Dim];
160 };
161 
163 template<int Dim>
165  : m_numPoints(numPoints)
166  , m_wspdSeparationFactor(1.0)
167  , m_wspdSeparationFactorPlus2Squared_cached(9.0) {
168  // get the memory
169  allocate();
170 
171  // init arrays
172  for (int i = 0; i < Dim; i++) {
173  m_bboxMin[i] = m_bboxMax[i] = 0.0;
174  }
175 }
176 
178 template<int Dim>
180  // free the mem
181  deallocate();
182 }
183 
184 template<int Dim>
186  m_pTree = new Tree(m_numPoints);
187  m_nodeData = new NodeData[m_pTree->maxNumNodes()];
188  m_pointData = new PointData[m_numPoints];
189 }
190 
191 template<int Dim>
193  delete m_pTree;
194  delete[] m_nodeData;
195  delete[] m_pointData;
196 }
197 
198 template<int Dim>
200  // update the bounding box of the point set
201  updateBoundingBox();
202 
203  // update grid points inside the quadtree
204  updateTreeGridPoints();
205 
206  // rebuild the tree
207  m_pTree->build();
208 
209  // compute center, radius and bbox for each node
210  updateTreeNodeGeometry();
211 }
212 
213 template<int Dim>
215  m_pIWSPD = pIWSPD;
216 
217  // update this cached value for the well-sep test
218  const double s = (m_wspdSeparationFactor + 2.0);
219 
220  // precompute this
221  m_wspdSeparationFactorPlus2Squared_cached = s * s;
222 
223  // go ahead with the decomposition
224  wspdRecursive(m_pTree->rootIndex());
225 }
226 
227 // the unary recursive function generating the binary calls
228 template<int Dim>
230  // iterate over all ordered pairs of children
231  for (int i = 0; i < m_pTree->numChilds(curr); i++) {
232  // the first child index
233  const int first_child = m_pTree->child(curr, i);
234 
235  // the second loop for the pair
236  for (int j = i + 1; j < m_pTree->numChilds(curr); j++) {
237  // the second child index
238  const int second_child = m_pTree->child(curr, j);
239 
240  // call for each ordered pair the binary function
241  wspdRecursive(first_child, second_child);
242  }
243 
244  // now do all this for every child
245  wspdRecursive(first_child);
246  }
247 }
248 
249 template<int Dim>
250 void DTreeWSPD<Dim>::wspdRecursive(int a, int b) {
251  if (areWellSeparated(a, b)) {
252  // far enough away => approx
253  if (m_pIWSPD) {
254  m_pIWSPD->onWellSeparatedPair(a, b);
255  }
256  } else {
257  // two cells are too close
258  int small_node = a;
259  int large_node = b;
260 
261  // make sure the small one is not the bigger one
262  if (node(small_node).radius_sq > node(large_node).radius_sq) {
263  std::swap(small_node, large_node);
264  }
265 
266  // split the bigger one
267  for (int i = 0; i < tree().numChilds(large_node); ++i) {
268  // recurse on the child
269  wspdRecursive(small_node, tree().child(large_node, i));
270  }
271  }
272 }
273 
274 template<int Dim>
275 bool DTreeWSPD<Dim>::areWellSeparated(int a, int b) const {
276  // take the bigger radius
277  double r_max_sq = std::max(node(a).radius_sq, node(b).radius_sq);
278 
279  // compute the square distance
280  double dist_sq = 0.0;
281 
282  // the d^2 loop
283  for (int d = 0; d < Dim; d++) {
284  double dx = node(a).x[d] - node(b).x[d];
285  dist_sq += dx * dx;
286  }
287 
288  // two circles are well separated iff d - 2r > sr
289  // where d is the distance between the two centers
290  // (not the distance of circles!)
291  // this ws <=> d > (s + 2)r
292  // more efficient: d^2 > (s + 2)^2 r^2
293  // d_sq > (s^2 + 4s + 4) * r_max
294 #if 0
295 # if 0
296  const double s = (m_wspdSeparationFactor + 2.0);
297  return dist_sq > (m_wspdSeparationFactor * m_wspdSeparationFactor + 4.0 * m_wspdSeparationFactor + 4) * r_max * r_max;
298 # else
299  return dist_sq > s * s * r_max_sq;
300 # endif
301 #else
302  return dist_sq > m_wspdSeparationFactorPlus2Squared_cached * r_max_sq;
303 #endif
304 }
305 
306 template<>
307 bool DTreeWSPD<2>::areWellSeparated(int a, int b) const {
308  // take the bigger radius
309  double r_max_sq = std::max(node(a).radius_sq, node(b).radius_sq);
310 
311  // compute the square distance
312  double dx_0 = node(a).x[0] - node(b).x[0];
313  double dx_1 = node(a).x[1] - node(b).x[1];
314  double dist_sq = dx_0 * dx_0 + dx_1 * dx_1;
315 
316  // compare the sq distance
317  return dist_sq > m_wspdSeparationFactorPlus2Squared_cached * r_max_sq;
318 }
319 
320 template<>
321 bool DTreeWSPD<3>::areWellSeparated(int a, int b) const {
322  // take the bigger radius
323  double r_max_sq = std::max(node(a).radius_sq, node(b).radius_sq);
324 
325  // compute the square distance
326  double dx_0 = node(a).x[0] - node(b).x[0];
327  double dx_1 = node(a).x[1] - node(b).x[1];
328  double dx_2 = node(a).x[2] - node(b).x[2];
329  double dist_sq = dx_0 * dx_0 + dx_1 * dx_1 + dx_2 * dx_2;
330 
331  // compare the sq distance
332  return dist_sq > m_wspdSeparationFactorPlus2Squared_cached * r_max_sq;
333 }
334 
336 template<int Dim>
337 void DTreeWSPD<Dim>::setPoint(int i, int d, double coord) {
338  m_pointData[i].x[d] = coord;
339 }
340 
341 template<int Dim>
343  if (!m_numPoints) {
344  return;
345  }
346 
347  // initial values
348  for (int d = 0; d < Dim; d++) {
349  m_bboxMin[d] = m_bboxMax[d] = point(0).x[d];
350  }
351 
352  // no magic here
353  for (int i = 1; i < m_numPoints; i++) {
354  for (int d = 0; d < Dim; d++) {
355  m_bboxMin[d] = std::min(m_bboxMin[d], point(i).x[d]);
356  m_bboxMax[d] = std::max(m_bboxMax[d], point(i).x[d]);
357  }
358  }
359 }
360 
361 // updates the integer grid points in the quadtree
362 template<int Dim>
364  for (int d = 0; d < Dim; d++) {
365  double noise_max = (m_bboxMax[d] - m_bboxMin[d]) * 0.25;
366  m_bboxMax[d] += randomDouble(0.0, noise_max);
367  m_bboxMin[d] -= randomDouble(0.0, noise_max);
368  }
369  // lets assume the bbox is updated. find the longest side
370  double quad_size = m_bboxMax[0] - m_bboxMin[0];
371  for (int d = 1; d < Dim; d++) {
372  quad_size = std::max(quad_size, m_bboxMax[d] - m_bboxMin[d]);
373  }
374 
375  const double factor = (double)(0xffffffff);
376 
377  double scale = factor / quad_size;
378  // iterate over all points
379  for (int i = 0; i < m_numPoints; i++) {
380  for (int d = 0; d < Dim; d++) {
381  // put it in the bounding square
382 #if 0
383  double nx = ((point(i).x[d] - m_bboxMin[d] + 0.01) / quad_size + 0.02);
384 #endif
385  double nx = ((point(i).x[d] - m_bboxMin[d]) * scale);
386 
387  // dirty put on grid here
388  unsigned int ix = static_cast<unsigned int>(nx); //nx * (double)(unsigned int)(0x1fffffff);
389 
390  // set the point coord
391  m_pTree->setPoint(i, d, ix);
392  }
393  }
394 }
395 
396 template<int Dim>
398  updateTreeNodeGeometry(m_pTree->rootIndex());
399 }
400 
401 // updates the geometry of the quadtree nodes
402 template<int Dim>
404  // if this is an inner node
405  if (m_pTree->numChilds(curr)) {
406  // init with the bbox of the first child
407 
408  // iterate over the rest of the children
409  for (int i = 0; i < m_pTree->numChilds(curr); i++) {
410  // the child index
411  const int child = m_pTree->child(curr, i);
412 
413  // compute the size of the subtree
414  updateTreeNodeGeometry(child);
415 
416  // lazy set the first
417  if (!i) {
418  for (int d = 0; d < Dim; d++) {
419  node(curr).min_x[d] = node(child).min_x[d];
420  node(curr).max_x[d] = node(child).max_x[d];
421  }
422  } else {
423  for (int d = 0; d < Dim; d++) {
424  node(curr).min_x[d] = std::min(node(curr).min_x[d], node(child).min_x[d]);
425  node(curr).max_x[d] = std::max(node(curr).max_x[d], node(child).max_x[d]);
426  }
427  }
428  };
429  } else { // else it is a leaf
430  // init from first point
431  for (int d = 0; d < Dim; d++) {
432  node(curr).min_x[d] = node(curr).max_x[d] = point(tree().point(curr, 0)).x[d];
433  }
434 
435  // and the remaining points
436  for (int i = 1; i < tree().numPoints(curr); ++i) {
437  for (int d = 0; d < Dim; d++) {
438  node(curr).min_x[d] =
439  std::min(node(curr).min_x[d], point(tree().point(curr, i)).x[d]);
440  node(curr).max_x[d] =
441  std::max(node(curr).max_x[d], point(tree().point(curr, i)).x[d]);
442  }
443  }
444  }
445 
446  // init the radius
447  node(curr).radius_sq = 0.0;
448 
449  // compute the center and radius of the rect
450  for (int d = 0; d < Dim; d++) {
451  node(curr).x[d] = (node(curr).min_x[d] + node(curr).max_x[d]) * 0.5;
452  double s_x = (node(curr).max_x[d] - node(curr).min_x[d]);
453  node(curr).radius_sq += s_x * s_x;
454  }
455 
456  // and the smallest enclosing circle radius squared
457  node(curr).radius_sq *= 0.25; // sqrt(node(curr).radius) * 0.5 squared;
458 }
459 
460 }
461 }
462 }
ogdf
The namespace for all OGDF objects.
Definition: multilevelmixer.cpp:39
ogdf::energybased::dtree::DTreeWSPD::NodeData::min_x
double min_x[Dim]
bounding box min coord
Definition: DTreeWSPD.h:65
DTree.h
ogdf::energybased::dtree::DTreeWSPD::m_nodeData
NodeData * m_nodeData
geometry for the quadtree nodes
Definition: DTreeWSPD.h:150
ogdf::energybased::dtree::DTreeWSPD::tree
const Tree & tree() const
returns the corresponding Dtree
Definition: DTreeWSPD.h:84
ogdf::energybased::dtree::IWSPD::onWellSeparatedPair
virtual void onWellSeparatedPair(int aIndex, int bIndex)=0
called by the WSPD for a pair that is well separated
ogdf::energybased::dtree::DTreeWSPD::deallocate
void deallocate()
free mem
Definition: DTreeWSPD.h:192
ogdf::energybased::dtree::DTreeWSPD::NodeData::x
double x[Dim]
center of cell circle
Definition: DTreeWSPD.h:62
ogdf::energybased::dtree::DTreeWSPD::m_pointData
PointData * m_pointData
point data
Definition: DTreeWSPD.h:153
ogdf::energybased::dtree::DTreeWSPD::~DTreeWSPD
~DTreeWSPD()
destructor
Definition: DTreeWSPD.h:179
ogdf::energybased::dtree::DTreeWSPD::setSeparationFactor
void setSeparationFactor(double s)
sets the parameter s of the WSPD (default is 1.0)
Definition: DTreeWSPD.h:102
ogdf::energybased::dtree::DTreeWSPD::NodeData::max_x
double max_x[Dim]
bounding box min coord
Definition: DTreeWSPD.h:68
ogdf::energybased::dtree::DTreeWSPD::update
void update()
call this when the point set has been updated.
Definition: DTreeWSPD.h:199
ogdf::energybased::dtree::DTreeWSPD::updateBoundingBox
void updateBoundingBox()
updates the bounding box by iterating over all points
Definition: DTreeWSPD.h:342
ogdf::energybased::dtree::DTreeWSPD::node
const NodeData & node(int i) const
returns the data for a quadtree
Definition: DTreeWSPD.h:87
ogdf::energybased::dtree::DTreeWSPD::m_numPoints
int m_numPoints
number of points
Definition: DTreeWSPD.h:138
ogdf::energybased::dtree::DTreeWSPD::NodeData::radius_sq
double radius_sq
radius of the cell
Definition: DTreeWSPD.h:71
ogdf::energybased::dtree::DTreeWSPD::NodeData
geometry for the quadtree nodes
Definition: DTreeWSPD.h:60
ogdf::energybased::dtree::DTreeWSPD::updateTreeNodeGeometry
void updateTreeNodeGeometry()
updates the geometry of the quadtree nodes
Definition: DTreeWSPD.h:397
ogdf::energybased::dtree::DTreeWSPD::PointData
world coordinates of the points
Definition: DTreeWSPD.h:75
ogdf::energybased::dtree::DTreeWSPD::node
NodeData & node(int i)
returns the data for a quadtree
Definition: DTreeWSPD.h:108
ogdf::energybased::dtree::DTreeWSPD::wspdRecursive
void wspdRecursive(int a)
the unary recursive function generating the binary calls
Definition: DTreeWSPD.h:229
ogdf::energybased::dtree::DTreeWSPD::separationFactor
double separationFactor() const
returns the parameter s of the WSPD (default is 1.0)
Definition: DTreeWSPD.h:99
ogdf::energybased::dtree::DTreeWSPD::m_bboxMin
double m_bboxMin[Dim]
the bounding box min coord of the point set
Definition: DTreeWSPD.h:156
ogdf::energybased::dtree::IWSPD
Definition: DTreeWSPD.h:41
ogdf::energybased::dtree::DTreeWSPD::computeWSPD
void computeWSPD(IWSPD *m_pIWSPD)
Definition: DTreeWSPD.h:214
ogdf::node
NodeElement * node
The type of nodes.
Definition: Graph_d.h:70
ogdf::energybased::dtree::DTreeWSPD::IntType
unsigned int IntType
Definition: DTreeWSPD.h:50
ogdf::energybased::dtree::DTreeWSPD::m_wspdSeparationFactorPlus2Squared_cached
double m_wspdSeparationFactorPlus2Squared_cached
a cached value for the ws test
Definition: DTreeWSPD.h:144
ogdf::energybased::dtree::DTreeWSPD::m_bboxMax
double m_bboxMax[Dim]
the bounding box max coord of the point set
Definition: DTreeWSPD.h:159
ogdf::EdgeStandardType::tree
@ tree
for every hyperedge e a minimal subcubic tree connecting all hypernodes incident with e together is a...
ogdf::energybased::dtree::DTreeWSPD::m_pIWSPD
IWSPD * m_pIWSPD
Definition: DTreeWSPD.h:105
basic.h
Basic declarations, included by all source files.
ogdf::energybased::dtree::DTreeWSPD::PointData::x
double x[Dim]
coords of the point
Definition: DTreeWSPD.h:77
ogdf::energybased::dtree::DTreeWSPD
Definition: DTreeWSPD.h:48
ogdf::energybased::dtree::DTreeWSPD::point
const PointData & point(int i) const
return ith point
Definition: DTreeWSPD.h:93
ogdf::energybased::dtree::DTreeWSPD::m_wspdSeparationFactor
double m_wspdSeparationFactor
the separation factor for the ws predicate
Definition: DTreeWSPD.h:141
ogdf::energybased::dtree::DTreeWSPD::DTreeWSPD
DTreeWSPD(int numPoints)
constructs a new WSPD for numPoints
Definition: DTreeWSPD.h:164
ogdf::energybased::dtree::DTreeWSPD::setPoint
void setPoint(int i, int d, double coord)
sets the point to the given coords
Definition: DTreeWSPD.h:337
ogdf::energybased::dtree::DTreeWSPD::allocate
void allocate()
allocate mem
Definition: DTreeWSPD.h:185
ogdf::energybased::dtree::DTree
Implentation of the reduced quadtree for Dim dimensions.
Definition: DTree.h:41
ogdf::energybased::dtree::DTreeWSPD::updateTreeGridPoints
void updateTreeGridPoints()
updates the integer grid points in the quadtree
Definition: DTreeWSPD.h:363
ogdf::energybased::dtree::DTreeWSPD::areWellSeparated
bool areWellSeparated(int a, int b) const
predicate for determining if cells are well-separated
Definition: DTreeWSPD.h:275
ogdf::randomDouble
double randomDouble(double low, double high)
Returns a random double value from the interval [low, high).
ogdf::energybased::dtree::DTreeWSPD::m_pTree
Tree * m_pTree
the quadtree this wspd is working on
Definition: DTreeWSPD.h:147