Open
Graph Drawing
Framework

 v. 2023.09 (Elderberry)
 

Loading...
Searching...
No Matches
DTreeEmbedder.h
Go to the documentation of this file.
1
29#pragma once
30
33
34namespace ogdf {
35namespace energybased {
36namespace dtree {
37
38template<int Dim>
40public:
42 explicit DTreeEmbedder(const Graph& graph);
43
45 virtual ~DTreeEmbedder();
46
48 double position(node v, int d) const;
49
51 void setPosition(node v, int d, double coord);
52
54 double mass(node v) const;
55
57 void setMass(node v, double mass);
58
60 double edgeWeight(edge e) const;
61
63 void setEdgeWeight(edge e, double weight);
64
66 void resetForces();
67
69 template<typename ForceFunc, bool UseForcePrime>
71
73 template<typename ForceFunc, bool UseForcePrime>
75
77 template<typename ForceFunc, bool UseForcePrime>
79
81 template<typename AttrForceFunc, bool UseForcePrime>
83
84#if 0
87#endif
88
90 double moveNodes(double timeStep);
91 double moveNodesByForcePrime();
92
93#if 0
95 template<typename RepForceFunc>
97
100
102 template<typename RepForceFunc>
103 void doIterations(int numIterations, double epsilon, RepForceFunc repForceFunc);
104
106 template<typename RepForceFunc>
107 void doIterations(int numIterations, double epsilon);
108#endif
109
111 template<typename RepForceFunc, typename AttrForceFunc, bool UseForcePrime>
114
115 template<typename RepForceFunc, typename AttrForceFunc>
118
119 template<typename RepForceFunc, typename AttrForceFunc>
122
123#if 0
124 template<typename RepForceFunc>
126#endif
127
129 const Graph& graph() const;
130
132 void centerNodesAt(double centerBBox[Dim]);
133
135 void scaleNodes(double scaleFactor);
136
137private:
139 struct NodeInfo {
141 double position[Dim];
142
144 double force[Dim];
145
148
150 double mass;
151 };
152
155
158
161
164
166
168};
169
172
173template<int Dim>
174DTreeEmbedder<Dim>::DTreeEmbedder(const Graph& graph) : m_graph(graph) {
176 m_nodeInfo.init(m_graph);
177 for (node v = m_graph.firstNode(); v; v = v->succ()) {
178 m_nodeInfo[v].mass = 1.0;
179 }
180
183 m_defaultTimeStep = 0.125;
184}
185
186template<int Dim>
188 delete m_pTreeForce;
189}
190
191template<int Dim>
192template<typename ForceFunc, bool UseForcePrime>
194 double delta[Dim];
195 double force;
196 double force_prime;
197 for (node s = m_graph.firstNode(); s; s = s->succ()) {
198 for (node t = s->succ(); t; t = t->succ()) {
199 double dist = computeDeltaAndDistance<Dim>(m_nodeInfo[s].position,
200 m_nodeInfo[t].position, delta);
201
202 // evaluate the force function
203 forceFunc(dist, force, force_prime);
204
205 force = force / dist * mass(s) * mass(t);
206
207 // add the force to the existing
208 for (int d = 0; d < Dim; d++) {
209 m_nodeInfo[s].force[d] += force * delta[d];
210 m_nodeInfo[t].force[d] -= force * delta[d];
211 }
212
213 if (UseForcePrime) {
214 force_prime = force_prime * mass(s) * mass(t);
215 m_nodeInfo[s].force_prime += force_prime;
216 m_nodeInfo[t].force_prime += force_prime;
217 }
218 }
219 }
220}
221
222#if 0
223template<int Dim>
224template<typename ForceFunc>
226{
227 double delta[Dim];
228 double force;
229 for (node s = m_graph.firstNode(); s; s = s->succ()) {
230 for (node t = s->succ(); t; t = t->succ()) {
231 double dist = computeDeltaAndDistance<Dim>(m_nodeInfo[s].position, m_nodeInfo[t].position, delta);
232
233 // evaluate the force function
234 forceFunc(dist, force);
235
236 force = force / dist * mass(s) * mass(t);
237
238 // add the force to the existing
239 for (int d = 0; d < Dim; d++) {
240 m_nodeInfo[s].force[d] += force * delta[d];
241 m_nodeInfo[s].force[d] += force * delta[d];
242 }
243 }
244 }
245}
246#endif
247
248template<int Dim>
249template<typename ForceFunc, bool UseForcePrime>
251 int currIndex = 0;
252 // loop over all nodes
253 for (node v = m_graph.firstNode(); v; v = v->succ()) {
254 // update the node pos in the tree data structure
255 for (int d = 0; d < Dim; d++) {
256 m_pTreeForce->setPosition(currIndex, d, m_nodeInfo[v].position[d]);
257 }
258
259 // update the mass
260 m_pTreeForce->setMass(currIndex, m_nodeInfo[v].mass);
261 currIndex++;
262 }
263
264 // run the approximation
266
267 // reset the index
268 currIndex = 0;
269
270 // loop over all nodes
271 for (node v = m_graph.firstNode(); v; v = v->succ()) {
272 // read back the forces
273 for (int d = 0; d < Dim; d++) {
274 m_nodeInfo[v].force[d] += m_pTreeForce->force(currIndex, d);
275 }
276
277 if (UseForcePrime) {
278 m_nodeInfo[v].force_prime += m_pTreeForce->force_prime(currIndex);
279 }
280
281 currIndex++;
282 }
283}
284
285#if 0
286template<int Dim>
287template<typename ForceFunc>
289{
290 int currIndex = 0;
291 // loop over all nodes
292 for (node v = m_graph.firstNode(); v; v = v->succ()) {
293 // update the node pos in the tree data structure
294 for (int d = 0; d < Dim; d++) {
295 m_pTreeForce->setPosition(currIndex, d, m_nodeInfo[v].position[d]);
296 }
297
298 // update the mass
299 m_pTreeForce->setMass(currIndex, m_nodeInfo[v].mass);
300 currIndex++;
301 }
302
303 // run the approximation
304 m_pTreeForce->template computeForces<ForceFunc, true>(forceFunc);
305
306 // reset the index
307 currIndex = 0;
308
309 // loop over all nodes
310 for (node v = m_graph.firstNode(); v; v = v->succ()) {
311 // read back the forces
312 for (int d = 0; d < Dim; d++) {
313 m_nodeInfo[v].force[d] += m_pTreeForce->force(currIndex, d);
314 }
315
316 currIndex++;
317 }
318}
319#endif
320
321template<int Dim>
322template<typename ForceFunc, bool UseForcePrime>
324 if (m_graph.numberOfNodes() <= m_maxNumNodesExactRepForces) {
326 } else {
328 }
329}
330
331#if 0
332template<int Dim>
333template<typename ForceFunc>
335{
336 if (m_graph.numberOfNodes() <= m_maxNumNodesExactRepForces) {
338 } else {
340 }
341}
342#endif
343
344template<int Dim>
345template<typename AttrForceFunc, bool UseForcePrime>
347 // for all edges
348 for (edge e = m_graph.firstEdge(); e; e = e->succ()) {
349 node s = e->source();
350 node t = e->target();
351
352 // check if this is a self loop
353 if (s == t) {
354 continue;
355 }
356
357 // s t delta vector
358 double delta[Dim];
359
360 // var for the squared distance of s and t
361 double dist_sq = 0.0;
362
363 // compute delta and sum up dist_sq
364 for (int d = 0; d < Dim; d++) {
365 delta[d] = m_nodeInfo[t].position[d] - m_nodeInfo[s].position[d];
366 dist_sq += delta[d] * delta[d];
367 }
368
369 // we take the log of the squared distance here
370#if 0
371 double f = log(dist_sq) * 0.5;
372#endif
373 double dist = (sqrt(dist_sq));
374
375 double f;
376 double f_prime;
377
378 if (UseForcePrime) {
380
381 f_prime *= m_edgeWeight[e];
382
383 m_nodeInfo[s].force_prime += f_prime;
384 m_nodeInfo[t].force_prime += f_prime;
385 } else {
387 }
388
389 f *= m_edgeWeight[e];
390
391 // compute delta and sum up dist_sq
392 for (int d = 0; d < Dim; d++) {
393 m_nodeInfo[s].force[d] += f * delta[d] / dist; // * s_scale;
394 m_nodeInfo[t].force[d] -= f * delta[d] / dist; // * t_scale;
395 }
396 }
397}
398
399#if 0
400template<int Dim>
401template<typename AttrForceFunc>
403{
404 // for all edges
405 for (edge e = m_graph.firstEdge(); e; e = e->succ()) {
406 node s = e->source();
407 node t = e->target();
408
409 // check if this is a self loop
410 if (s == t) {
411 continue;
412 }
413
414 // s t delta vector
415 double delta[Dim];
416
417 // var for the squared distance of s and t
418 double dist_sq = 0.0;
419
420 // compute delta and sum up dist_sq
421 for (int d = 0; d < Dim; d++) {
422 delta[d] = m_nodeInfo[t].position[d] - m_nodeInfo[s].position[d];
423 dist_sq += delta[d] * delta[d];
424 }
425
426 // we take the log of the squared distance here
427# if 0
428 double f = log(dist_sq) * 0.5;
429# endif
430 double dist = (sqrt(dist_sq));
431 double f = (dist) * (dist) * m_edgeWeight[e];
432 double f_prime = 2.0 * dist * m_edgeWeight[e];
433 // for scaling the force accordingly
434# if 0
435 double s_scale = 1.0/(double)s->degree();
436 double t_scale = 1.0/(double)t->degree();
437# endif
438
439 m_nodeInfo[s].force_prime += f_prime;
440 m_nodeInfo[t].force_prime += f_prime;
441
442 // compute delta and sum up dist_sq
443 for (int d = 0; d < Dim; d++) {
444 m_nodeInfo[s].force[d] += f * delta[d] / dist;// * s_scale;
445 m_nodeInfo[t].force[d] -= f * delta[d] / dist;// * t_scale;
446 }
447 }
448}
449
450template<int Dim>
451void DTreeEmbedder<Dim>::computeEdgeForcesSq()
452{
453 for (node s = m_graph.firstNode(); s; s = s->succ()) {
454 double sum_f[Dim];
455 double sum_df[Dim];
456
457 double sum_ddf = 0.0;
458 // compute delta and sum up dist_sq
459 for (int d = 0; d < Dim; d++) {
460 sum_f[d] = 0.0;
461 sum_df[d] = 0.0;
462 }
463
464 for (adjEntry adj = s->firstAdj(); adj; adj = adj->succ()) {
465 node t = adj->twinNode();
466
467 // check if this is a self loop
468 if (s == t)
469 continue;
470
471 // s t delta vector
472 double delta[Dim];
473
474 // var for the squared distance of s and t
475 double dist_sq = 0.0;
476
477 // compute delta and sum up dist_sq
478 for (int d = 0; d < Dim; d++) {
479 delta[d] = m_nodeInfo[t].position[d] - m_nodeInfo[s].position[d];
480 dist_sq += delta[d] * delta[d];
481 }
482
483 double dist = sqrt(dist_sq);
484
485 double f = 1.0;
486 double df = 1.0;
487 // compute delta and sum up dist_sq
488 for (int d = 0; d < Dim; d++) {
489 sum_f[d] += f * delta[d] / dist;
490
491 }
492 sum_ddf += df;
493 }
494 for (int d = 0; d < Dim; d++) {
495 m_nodeInfo[s].force[d] = m_nodeInfo[s].force[d] + sum_f[d] / sum_ddf;
496 }
497 }
498}
499#endif
500
501template<int Dim>
503 // the maximum displacement
504 double maxDispl = 0.0;
505
506 // loop over all nodes
507 for (node v = m_graph.firstNode(); v; v = v->succ()) {
508 double displ_sq = 0.0;
509 // update the position by the force vec
510 for (int d = 0; d < Dim; d++) {
511 double displ = m_nodeInfo[v].force[d] / m_nodeInfo[v].force_prime;
512 m_nodeInfo[v].position[d] += displ;
513 displ_sq += displ * displ;
514 }
515
516 // we compare the square of the distance to save the sqrt here
517 if (maxDispl < displ_sq) {
519 }
520 }
521 Logger::slout() << "sqrt(maxDispl)=" << sqrt(maxDispl) << std::endl;
522 return sqrt(maxDispl);
523}
524
525template<int Dim>
526double DTreeEmbedder<Dim>::moveNodes(double timeStep) {
527 // the maximum displacement
528 double maxDispl = 0.0;
529
530 // loop over all nodes
531 for (node v = m_graph.firstNode(); v; v = v->succ()) {
532 double displ_sq = 0.0;
533 // update the position by the force vec
534 for (int d = 0; d < Dim; d++) {
535 double displ = m_nodeInfo[v].force[d] * timeStep;
536 m_nodeInfo[v].position[d] += displ;
537 displ_sq += displ * displ;
538 }
539
540 // we compare the square of the distance to save the sqrt here
541 if (maxDispl < displ_sq) {
543 }
544 }
545
546 Logger::slout() << "sqrt(maxDispl)=" << sqrt(maxDispl) << std::endl;
547 return sqrt(maxDispl);
548}
549
550template<int Dim>
552 // loop over all nodes
553 for (node v = m_graph.firstNode(); v; v = v->succ()) {
554 // reset the force vector
555 for (int d = 0; d < Dim; d++) {
556 m_nodeInfo[v].force[d] = 0.0;
557 }
558 m_nodeInfo[v].force_prime = 0.0;
559 }
560}
561
562#if 0
563template<int Dim>
564template<typename RepForceFunc, bool>
566{
567 // reset forces
568 resetForces();
569
570 // the repulsive forces
571 computeRepForces(repForceFunc);
572
573 // edge forces
574 computeEdgeForces();
575
576 // move the nodes
577 return moveNodes(m_defaultTimeStep);
578}
579
580template<int Dim>
581template<typename RepForceFunc>
582void DTreeEmbedder<Dim>::doIterations(int numIterations, double epsilon, RepForceFunc repForceFunc)
583{
584 // init the error with epsilon
585 double maxDisplacement = epsilon;
586
587 // while error too big and we have iterations left
588 for (int i = 0; i < numIterations && maxDisplacement >= epsilon; ++i) {
589 // run it
590 maxDisplacement = doIteration(repForceFunc);
591 }
592}
593
594template<int Dim>
595template<typename RepForceFunc>
596void DTreeEmbedder<Dim>::doIterationsAdaptive(int numIterations, double epsilon, RepForceFunc repForceFunc)
597{
598 int iterationsUsed = 0;
599 // the current timeStep
600
601 double maxTimeStep = 1.0;
602 double timeStep = m_defaultTimeStep;
603
604 int progress = 0;
605 // scaling factor for the adaptive timeStep
606 double t = 0.99;
607
608 // init the error with epsilon
609 double maxDisplacement = 100000000.0;
610
611 // value that keeps track of the displacement
612 double lastMaxDisplacement = 0.0;
613
614 // while error too big and we have iterations left
615 for (int i = 0; i < numIterations && maxDisplacement >= epsilon; ++i) {
616 // reset forces
617 resetForces();
618
619 // the repulsive forces
620 computeRepForces(repForceFunc);
621
622 // edge forces
623 computeEdgeForces();
624
625 // move the nodes
626 maxDisplacement = moveNodes(timeStep);
627
628 // if this is not the first iteration
629 if (i > 0) {
630 if (maxDisplacement < lastMaxDisplacement * t) {
631 progress++;
632 timeStep = std::min(timeStep / t, maxTimeStep);
633 } else if (maxDisplacement > lastMaxDisplacement / t) {
634 timeStep = timeStep * t;
635 }
636 }
637 // save the maxDisplacement
638 lastMaxDisplacement = maxDisplacement;
640# if 0
641 Logger::slout() << maxDisplacement << std::endl;
642# endif
643 }
644 Logger::slout() << "IterationsUsed: " << iterationsUsed << " of " << numIterations << " energy: " << lastMaxDisplacement << std::endl;
645}
646
647template<int Dim>
648struct MyVec
649{
650 double x[Dim];
651};
652#endif
653
654template<int Dim>
655template<typename RepForceFunc, typename AttrForceFunc, bool UseForcePrime>
658 if (m_graph.numberOfNodes() < 2) {
659 return;
660 }
661
662 int numIterationsUsed = 0;
664 << "doIterationsNewton: V = " << m_graph.numberOfNodes()
665 << " E = " << m_graph.numberOfEdges() << " Iterations " << numIterations << std::endl;
666
667 // init the error with epsilon
668 double maxDisplacement = 10000.0;
669
670 // while error too big and we have iterations left
671 for (int i = 0; i < numIterations && maxDisplacement > epsilon; ++i) {
673 // reset forces
674 resetForces();
675
676 // the repulsive forces
678
679 // edge forces
681
682 // move the nodes
683 if (UseForcePrime) {
684 maxDisplacement = moveNodesByForcePrime();
685 } else {
686 maxDisplacement = moveNodes(0.1);
687 }
688 }
689
690 Logger::slout() << "Needed " << numIterationsUsed << " of " << numIterations << std::endl;
691}
692
693template<int Dim>
694template<typename RepForceFunc, typename AttrForceFunc>
700
701template<int Dim>
702template<typename RepForceFunc, typename AttrForceFunc>
708
709template<int Dim>
711 double bboxMin[Dim];
712 double bboxMax[Dim];
713
714 // initial values
715 for (int d = 0; d < Dim; d++) {
716 bboxMin[d] = bboxMax[d] = position(m_graph.firstEdge(), d);
717 }
718
719 // no magic here
720 for (node v = m_graph.firstNode(); v; v = v->succ()) {
721 for (int d = 0; d < Dim; d++) {
722 bboxMin[d] = std::min(bboxMin[d], position(v, d));
723 bboxMax[d] = std::max(bboxMax[d], position(v, d));
724 }
725 }
726
727 double delta[Dim];
728 for (int d = 0; d < Dim; d++) {
729 delta[d] = -(bboxMin[d] + bboxMax[d]) * 0.5;
730 }
731
732 for (node v = m_graph.firstNode(); v; v = v->succ()) {
733 for (int d = 0; d < Dim; d++) {
734 setPosition(v, d, delta[d]);
735 }
736 }
737}
738
739template<int Dim>
740void DTreeEmbedder<Dim>::scaleNodes(double scaleFactor) {
741 for (node v = m_graph.firstNode(); v; v = v->succ()) {
742 for (int d = 0; d < Dim; d++) {
743 setPosition(v, d, position(v, d) * scaleFactor);
744 }
745 }
746}
747
748template<int Dim>
749double DTreeEmbedder<Dim>::position(node v, int d) const {
750 return m_nodeInfo[v].position[d];
751}
752
753template<int Dim>
754void DTreeEmbedder<Dim>::setPosition(node v, int d, double coord) {
755 m_nodeInfo[v].position[d] = coord;
756}
757
758template<int Dim>
760 return m_nodeInfo[v].mass;
761}
762
763template<int Dim>
764void DTreeEmbedder<Dim>::setMass(node v, double mass) {
765 m_nodeInfo[v].mass = mass;
766}
767
768template<int Dim>
770 return m_graph;
771}
772
773template<int Dim>
775 m_edgeWeight[e] = weight;
776}
777
778template<int Dim>
780 return m_edgeWeight[e];
781}
782
783}
784}
785}
adjEntry succ() const
Returns the successor in the adjacency list.
Definition Graph_d.h:155
Dynamic arrays indexed with edges.
Definition EdgeArray.h:125
void init()
Reinitializes the array. Associates the array with no graph.
Definition EdgeArray.h:292
Class for the representation of edges.
Definition Graph_d.h:300
Data type for general directed graphs (adjacency list representation).
Definition Graph_d.h:521
int numberOfNodes() const
Returns the number of nodes in the graph.
Definition Graph_d.h:622
node firstNode() const
Returns the first node in the list of all nodes.
Definition Graph_d.h:646
static std::ostream & slout(Level level=Level::Default)
stream for logging-output (global)
Definition Logger.h:167
Dynamic arrays indexed with nodes.
Definition NodeArray.h:125
Class for the representation of nodes.
Definition Graph_d.h:177
int degree() const
Returns the degree of the node (indegree + outdegree).
Definition Graph_d.h:220
node succ() const
Returns the successor in the list of all nodes.
Definition Graph_d.h:229
adjEntry firstAdj() const
Returns the first entry in the adjaceny list.
Definition Graph_d.h:223
void centerNodesAt(double centerBBox[Dim])
computes the bounding box and all nodes are translated such that bbox center is at centerBBox
NodeArray< NodeInfo > m_nodeInfo
node states of all nodes
void doIterationsNewton(int numIterations, double epsilon, RepForceFunc repForceFunc, AttrForceFunc attrForceFunc)
void setMass(node v, double mass)
sets the mass of a node v
DTreeEmbedder(const Graph &graph)
constructor with a given graph, allocates memory and does initialization
void computeEdgeForces(AttrForceFunc attrForceFunc)
computes the edge forces for one iteration
void computeRepForces(ForceFunc forceFunc)
computes the repulsive forces
void setPosition(node v, int d, double coord)
sets the d-th coordinate of node v to coord
void doIterationsTempl(int numIterations, double epsilon, RepForceFunc repForceFunc, AttrForceFunc attrForceFunc)
does multiple iterations using the given repulsive force function
void resetForces()
sets the forces of all nodes to 0
void doIterationsStandard(int numIterations, double epsilon, RepForceFunc repForceFunc, AttrForceFunc attrForceFunc)
double position(node v, int d) const
returns the d-th coordinate of node v
const Graph & graph() const
returns the graph
double moveNodes(double timeStep)
moves the nodes by the computed force vector
DTreeForce< Dim > * m_pTreeForce
the tree force approx
void computeRepForcesExact(ForceFunc forceFunc)
computes the repulsive forces for one iteration in O(n^2)
EdgeArray< double > m_edgeWeight
the weight of the edges
void computeRepForcesApprox(ForceFunc forceFunc)
uses the tree code to approximate the repulsive forces in O(nlogn) for one iteration
double mass(node v) const
returns the mass of node v
double edgeWeight(edge e) const
returns the edge weight
void setEdgeWeight(edge e, double weight)
sets the weight of an edge
void scaleNodes(double scaleFactor)
changes the position of nodes according to a given scale factor
AdjElement * adjEntry
The type of adjacency entries.
Definition Graph_d.h:72
NodeElement * node
The type of nodes.
Definition Graph_d.h:64
static MultilevelBuilder * getDoubleFactoredZeroAdjustedMerger()
The namespace for all OGDF objects.