1 /** \file
2 * \brief DTreeStuff
3 *
4 * \author Martin Gronemann
5 *
6 * \par License:
7 * This file is part of the Open Graph Drawing Framework (OGDF).
8 *
9 * \par
10 * Copyright (C)<br>
11 * See README.md in the OGDF root directory for details.
12 *
13 * \par
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * Version 2 or 3 as published by the Free Software Foundation;
17 * see the file LICENSE.txt included in the packaging of this file
18 * for details.
19 *
20 * \par
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * \par
27 * You should have received a copy of the GNU General Public
28 * License along with this program; if not, see
29 * http://www.gnu.org/copyleft/gpl.html
30 */
31
32 #include <ogdf/energybased/dtree/GalaxyLevel.h>
33 #include <ogdf/basic/simple_graph_alg.h>
34
35 using namespace ogdf;
36 using namespace ogdf::energybased::dtree;
37
38 // public constructor for creating a coarser level
GalaxyLevel(const Graph & graph)39 GalaxyLevel::GalaxyLevel(const Graph& graph)
40 {
41 // sets the input graph by some not so nice cast
42 // but we are not changing it anyways so it is fine
43 m_pGraph = const_cast<Graph*>(&graph);
44
45 // set the next finer to the input
46 m_pNextFiner = nullptr;
47
48 // this is the coarsest so far
49 m_pNextCoarser = nullptr;
50
51 // init the node data
52 m_nodeWeight.init(*m_pGraph, 1.0);
53
54 // init the parent pointer node
55 m_parent.init(*m_pGraph, nullptr);
56
57 // init the edge weight with 1.0
58 m_edgeWeight.init(*m_pGraph, 1.0);
59 }
60
61 // private constructor for creating a coarser level
GalaxyLevel(GalaxyLevel * pNextFiner)62 GalaxyLevel::GalaxyLevel(GalaxyLevel* pNextFiner)
63 {
64 // create a new empty graph
65 m_pGraph = new Graph();
66
67 // set the next finer to the input
68 m_pNextFiner = pNextFiner;
69
70 // this is the coarsest so far
71 m_pNextCoarser = nullptr;
72
73 // and link the other way around
74 m_pNextFiner->m_pNextCoarser = this;
75
76 // init the node data
77 m_nodeWeight.init(*m_pGraph, 0.0);
78
79 // init the parent pointer node
80 m_parent.init(*m_pGraph, nullptr);
81
82 // init the edge weight with 0.0 for summming up
83 m_edgeWeight.init(*m_pGraph, 0.0);
84 }
85
~GalaxyLevel()86 GalaxyLevel::~GalaxyLevel()
87 {
88 // delete the rest of the chain
89 delete m_pNextCoarser;
90
91 // if this is not the original graph
92 if (m_pNextFiner) {
93 // set this pointer to 0 in case someone
94 // is deleting in the middle of the chain
95 m_pNextFiner->m_pNextCoarser = nullptr;
96
97 // delete the graph
98 delete m_pGraph;
99 }
100 }
101
102 struct SunWeightComparer
103 {
104 // constructor with a node array for the weight
SunWeightComparerSunWeightComparer105 explicit SunWeightComparer(const NodeArray<double>& weight) : m_weight(weight) { }
106
107 // compares the two weights
operator ()SunWeightComparer108 bool operator()(node a, node b) const { return m_weight[a] < m_weight[b]; }
109
110 // the node array
111 const NodeArray<double>& m_weight;
112 };
113
buildNextCoarserLevel(int numLabels)114 GalaxyLevel* GalaxyLevel::buildNextCoarserLevel(int numLabels)
115 {
116 // make sure the graph is connected
117 OGDF_ASSERT(isConnected(*m_pGraph));
118
119 // keeps for each node the estimated sunweight
120 NodeArray<double> sunWeight(*m_pGraph, 0.0);
121
122 // iterate over all nodes
123 for (node v = m_pGraph->firstNode(); v; v = v->succ()) {
124 // init with the nodes weight
125 sunWeight[v] = m_nodeWeight[v];
126
127 // and add all adjacent weights
128 for (adjEntry adj = v->firstAdj(); adj; adj = adj->succ()) {
129 // sum up the weight
130 sunWeight[v] += m_nodeWeight[adj->twinNode()];
131 }
132 }
133
134 // array of nodes for sorting them by sunweight
135 Array<node> sortedOrder(m_pGraph->numberOfNodes());
136 m_pGraph->allNodes(sortedOrder);
137
138 // shuffle them to avoid artifacts from the initial order
139 std::random_shuffle(sortedOrder.begin(), sortedOrder.end());
140
141 // sort them, we want the suns with low weight
142 std::sort(sortedOrder.begin(), sortedOrder.end(), SunWeightComparer(sunWeight));
143
144 // the labels
145 NodeArray<int> label(*m_pGraph, numLabels);
146
147 // the sun of a node in the same graph
148 NodeArray<node> sun(*m_pGraph, nullptr);
149
150 // list of suns
151 List<node> sunList;
152
153 // while there is something to do
154 for (int i = 0; i < m_pGraph->numberOfNodes(); i++) {
155 // get a node
156 node s = sortedOrder[i];
157
158 // check if this is labeled
159 if (label[s] < numLabels)
160 continue;
161
162 // a nice queue
163 List<node> Q;
164
165 // mark it as sun
166 label[s] = 0;
167
168 // the sun of s is s
169 sun[s] = s;
170
171 // enqueue it
172 Q.pushBack(s);
173
174 // save it as a sun
175 sunList.pushBack(s);
176
177 // while there are nodes to label
178 while (!Q.empty()) {
179 // pop a labeled node from the queue
180 node u = Q.popFrontRet();
181
182 // the label for the next nodes
183 int newLabel = label[u] + 1;
184
185 // if we reached the limit do nothing
186 if (newLabel >= numLabels)
187 continue;
188
189 // label all adjacent nodes that are closer
190 for (adjEntry adj = u->firstAdj(); adj; adj = adj->succ()) {
191 // the adjacent one
192 node v = adj->twinNode();
193
194 // check if we can relabel
195 if (label[v] > newLabel) {
196 // set the new label
197 label[v] = newLabel;
198
199 // copy sun pointer
200 sun[v] = sun[u];
201
202 // enquee the new node
203 Q.pushBack(v);
204 }
205 }
206 }
207 };
208
209 // the new level to create
210 GalaxyLevel* pNewLevel = new GalaxyLevel(this);
211
212 // for all suns
213 for (node v : sunList) {
214 // create a copy on the next level
215 node v_new = pNewLevel->m_pGraph->newNode();
216
217 // set the parent of this sun
218 m_parent[v] = v_new;
219 }
220
221 // now for all nodes (notice that we will visit suns too)
222 for (node v = m_pGraph->firstNode(); v; v = v->succ()) {
223 // the sun of v
224 node s = sun[v];
225
226 // the parent of the sun
227 node s_parent = parent(s);
228
229 // add the weight to the new node
230 pNewLevel->m_nodeWeight[s_parent] += m_nodeWeight[v];
231
232 // the parent is the parent of the sun
233 m_parent[v] = s_parent;
234 }
235
236 // for all edges
237 for (edge e = m_pGraph->firstEdge(); e; e = e->succ()) {
238 // get the parents of the two endpoints
239 node s_new = parent(e->source());
240 node t_new = parent(e->target());
241
242 // check if parents are the same node
243 if (s_new == t_new)
244 continue;
245
246 // create a new edge
247 edge e_new = pNewLevel->m_pGraph->newEdge(s_new, t_new);
248
249 // save the old edge weight
250 pNewLevel->m_edgeWeight[e_new] = m_edgeWeight[e];
251 }
252
253 // removes all parallel edges and sum up weights
254 pNewLevel->removeParEdgesWithWeight();
255
256 // returns the new level
257 return pNewLevel;
258 }
259
removeParEdgesWithWeight()260 void GalaxyLevel::removeParEdgesWithWeight()
261 {
262 // keeps for each node the adj element from where we visited it
263 NodeArray<adjEntry> visitedFrom(*m_pGraph, nullptr);
264
265 // loop over all nodes
266 for (node v = m_pGraph->firstNode(); v; v = v->succ()) {
267 // the edges we have to del at the end
268 List<edge> toDel;
269
270 // for all adjacent nodes
271 for (adjEntry adj = v->firstAdj(); adj; adj = adj->succ()) {
272 // the adjacent node
273 node w = adj->twinNode();
274
275 // check if we visited and from where
276 if (visitedFrom[w] && (visitedFrom[w]->theNode() == v)) {
277 // we visited from v already, its a parallel edge
278 edge e = visitedFrom[w]->theEdge();
279
280 // add the edge weight to the parallel edge
281 m_edgeWeight[e] += m_edgeWeight[adj->theEdge()];
282
283 // and mark so we remove it later
284 toDel.pushBack(adj->theEdge());
285 } else {
286 // not visited from v, save the info from where we found w
287 visitedFrom[w] = adj;
288 }
289 }
290
291 // remove edges that we marked
292 while (!toDel.empty()) {
293 m_pGraph->delEdge(toDel.popFrontRet());
294 }
295 }
296 }
297
buildLevelsUntil(int maxNumNodes)298 GalaxyLevel* GalaxyLevel::buildLevelsUntil(int maxNumNodes)
299 {
300 // we start with this
301 GalaxyLevel* pLevel = this;
302
303 // fwd in case there are already levels created
304 while (pLevel->nextCoarser()) {
305 // go to the next
306 pLevel = pLevel->nextCoarser();
307 }
308
309 // while the curr level is too big
310 while (pLevel->graph().numberOfNodes() > maxNumNodes) {
311 // build a coarser one
312 pLevel = pLevel->buildNextCoarserLevel();
313 }
314
315 // return the coarsest level
316 return pLevel;
317 }
318
319 // returns the graph
graph() const320 const Graph& GalaxyLevel::graph() const
321 {
322 return *m_pGraph;
323 }
324
325 // returns the parent node of a node on the coarser level
parent(node v) const326 node GalaxyLevel::parent(node v) const
327 {
328 return m_parent[v];
329 }
330
331 // returns the weight of a node
weight(node v) const332 double GalaxyLevel::weight(node v) const
333 {
334 return m_nodeWeight[v];
335 }
336
337 // returns the weight of a node
edgeWeight(edge e) const338 double GalaxyLevel::edgeWeight(edge e) const
339 {
340 return m_edgeWeight[e];
341 }
342
343 // sets the weight of a node
setWeight(node v,double weight)344 void GalaxyLevel::setWeight(node v, double weight)
345 {
346 m_nodeWeight[v] = weight;
347 }
348
349 // sets the edge weight of e
setEdgeWeight(edge e,double weight)350 void GalaxyLevel::setEdgeWeight(edge e, double weight)
351 {
352 m_edgeWeight[e] = weight;
353 }
354
355 // returns true if this is the level of the original graph
isFinestLevel() const356 bool GalaxyLevel::isFinestLevel() const
357 {
358 return m_pNextFiner == nullptr;
359 }
360
361 // returns true if this is coarsest level in the chain
isCoarsestLevel() const362 bool GalaxyLevel::isCoarsestLevel() const
363 {
364 return m_pNextCoarser == nullptr;
365 }
366
367 // return the next coarser one
nextCoarser()368 GalaxyLevel* GalaxyLevel::nextCoarser()
369 {
370 return m_pNextCoarser;
371 }
372
373 // return the next finer one
nextFiner()374 GalaxyLevel* GalaxyLevel::nextFiner()
375 {
376 return m_pNextFiner;
377 }
378