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