6 * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $
7 ***************************************************************/
10 * \brief Implementation of algorithms for computing an
11 * acyclic subgraph (DfsAcyclicSubgraph, GreedyCycleRemovel)
13 * \author Carsten Gutwenger
16 * This file is part of the Open Graph Drawing Framework (OGDF).
20 * See README.txt in the root directory of the OGDF installation for details.
23 * This program is free software; you can redistribute it and/or
24 * modify it under the terms of the GNU General Public License
25 * Version 2 or 3 as published by the Free Software Foundation;
26 * see the file LICENSE.txt included in the packaging of this file
30 * This program is distributed in the hope that it will be useful,
31 * but WITHOUT ANY WARRANTY; without even the implied warranty of
32 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 * GNU General Public License for more details.
36 * You should have received a copy of the GNU General Public
37 * License along with this program; if not, write to the Free
38 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
39 * Boston, MA 02110-1301, USA.
41 * \see http://www.gnu.org/copyleft/gpl.html
42 ***************************************************************/
45 #include <ogdf/layered/DfsAcyclicSubgraph.h>
46 #include <ogdf/layered/GreedyCycleRemoval.h>
47 #include <ogdf/basic/simple_graph_alg.h>
48 #include <ogdf/basic/SList.h>
49 #include <ogdf/basic/GraphAttributes.h>
50 #include <ogdf/basic/Queue.h>
56 //---------------------------------------------------------
58 // computes a maximal acyclic subgraph by deleting all DFS
59 // backedges (linear-time)
60 //---------------------------------------------------------
62 void DfsAcyclicSubgraph::call (const Graph
&G
, List
<edge
> &arcSet
)
68 void DfsAcyclicSubgraph::callUML (
69 const GraphAttributes
&AG
,
72 const Graph
&G
= AG
.constGraph();
74 // identify hierarchies
75 NodeArray
<int> hierarchy(G
,-1);
82 if(hierarchy
[v
] == -1) {
83 int n
= dfsFindHierarchies(AG
,hierarchy
,count
,v
);
84 if(n
> 1) treeNum
= count
;
91 // perform DFS on the directed graph formed by generalizations
92 NodeArray
<int> number(G
,0), completion(G
);
93 int nNumber
= 0, nCompletion
= 0;
97 dfsBackedgesHierarchies(AG
,v
,number
,completion
,nNumber
,nCompletion
);
100 // collect all backedges within a hierarchy
101 // and compute outdeg of each vertex within its hierarchy
102 EdgeArray
<bool> reversed(G
,false);
103 NodeArray
<int> outdeg(G
,0);
107 if(AG
.type(e
) != Graph::generalization
|| e
->isSelfLoop())
110 node src
= e
->source(), tgt
= e
->target();
114 if (hierarchy
[src
] == hierarchy
[tgt
] &&
115 number
[src
] >= number
[tgt
] && completion
[src
] <= completion
[tgt
])
119 // topologial numbering of nodes within a hierarchy (for each hierarchy)
120 NodeArray
<int> numV(G
);
133 forall_adj_edges(e
,v
) {
134 node w
= e
->source();
142 // "direct" associations
144 if(AG
.type(e
) == Graph::generalization
|| e
->isSelfLoop())
147 node src
= e
->source(), tgt
= e
->target();
149 if(hierarchy
[src
] == hierarchy
[tgt
]) {
150 if (numV
[src
] < numV
[tgt
])
153 if(hierarchy
[src
] == treeNum
|| (hierarchy
[tgt
] != treeNum
&&
154 hierarchy
[src
] > hierarchy
[tgt
]))
159 // collect reversed edges
166 int DfsAcyclicSubgraph::dfsFindHierarchies(
167 const GraphAttributes
&AG
,
168 NodeArray
<int> &hierarchy
,
176 forall_adj_edges(e
,v
) {
177 if(AG
.type(e
) != Graph::generalization
)
180 node w
= e
->opposite(v
);
181 if(hierarchy
[w
] == -1)
182 count
+= dfsFindHierarchies(AG
,hierarchy
,i
,w
);
189 void DfsAcyclicSubgraph::dfsBackedgesHierarchies(
190 const GraphAttributes
&AG
,
192 NodeArray
<int> &number
,
193 NodeArray
<int> &completion
,
197 number
[v
] = ++nNumber
;
200 forall_adj_edges(e
,v
)
202 if(AG
.type(e
) != Graph::generalization
)
205 node w
= e
->target();
208 dfsBackedgesHierarchies(AG
,w
,number
,completion
,nNumber
,nCompletion
);
211 completion
[v
] = ++nCompletion
;
217 //---------------------------------------------------------
218 // GreedyCycleRemoval
219 // greedy heuristic for computing a maximal acyclic
220 // subgraph (linear-time)
221 //---------------------------------------------------------
223 void GreedyCycleRemoval::dfs (node v
, const Graph
&G
)
228 if (v
->outdeg() == 0) i
= m_min
;
229 else if (v
->indeg() == 0) i
= m_max
;
230 else i
= v
->outdeg() - v
->indeg();
232 m_item
[v
] = m_B
[m_index
[v
] = i
].pushBack(v
);
233 m_in
[v
] = v
->indeg();
234 m_out
[v
] = v
->outdeg();
238 forall_adj_edges(e
,v
) {
239 node u
= e
->opposite(v
);
246 void GreedyCycleRemoval::call (const Graph
&G
, List
<edge
> &arcSet
)
255 if (-v
->indeg () < m_min
) m_min
= -v
->indeg ();
256 if ( v
->outdeg() > m_max
) m_max
= v
->outdeg();
259 if (G
.numberOfEdges() == 0) return;
261 m_visited
.init(G
,false); m_item
.init(G
);
262 m_in
.init(G
); m_out
.init(G
);
263 m_index
.init(G
); m_B
.init(m_min
,m_max
);
265 SListPure
<node
> S_l
, S_r
;
266 NodeArray
<int> pos(G
);
270 if (m_visited
[v
]) continue;
273 int i
, max_i
= m_max
-1, min_i
= m_min
+1;
275 for ( ; m_counter
> 0; m_counter
--) {
276 if (!m_B
[m_min
].empty()) {
277 u
= m_B
[m_min
].front(); m_B
[m_min
].popFront();
280 } else if (!m_B
[m_max
].empty()) {
281 u
= m_B
[m_max
].front(); m_B
[m_max
].popFront();
285 while (m_B
[max_i
].empty())
287 while (m_B
[min_i
].empty())
290 if (abs(max_i
) > abs(min_i
)) {
291 u
= m_B
[max_i
].front(); m_B
[max_i
].popFront();
294 u
= m_B
[min_i
].front(); m_B
[min_i
].popFront();
299 m_item
[u
] = ListIterator
<node
>();
301 forall_adj_edges(e
,u
) {
302 if (e
->target() == u
) {
304 if (m_item
[w
].valid()) {
305 m_out
[w
]--; i
= m_index
[w
];
306 m_B
[i
].del(m_item
[w
]);
307 if (m_out
[w
] == 0) i
= m_min
;
308 else if (m_in
[w
] == 0) i
= m_max
;
310 m_item
[w
] = m_B
[m_index
[w
] = i
].pushBack(w
);
312 if (m_index
[w
] < min_i
)
317 if (m_item
[w
].valid()) {
318 m_in
[w
]--; i
= m_index
[w
];
319 m_B
[i
].del(m_item
[w
]);
320 if (m_out
[w
] == 0) i
= m_min
;
321 else if (m_in
[w
] == 0) i
= m_max
;
323 m_item
[w
] = m_B
[m_index
[w
] = i
].pushBack(w
);
325 if (m_index
[w
] > max_i
)
332 SListConstIterator
<node
> it
;
333 for(i
= 0, it
= S_l
.begin(); it
.valid(); ++it
)
335 for(it
= S_r
.begin(); it
.valid(); ++it
)
338 S_l
.clear(); S_r
.clear();
342 if (pos
[e
->source()] >= pos
[e
->target()])
345 m_visited
.init(); m_item
.init();
346 m_in
.init(); m_out
.init();
347 m_index
.init(); m_B
.init();
351 } // end namespace ogdf