6 * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $
7 ***************************************************************/
10 * \brief Declares & Implements a minimum-cut algorithmn according
11 * to an approach of Stoer and Wagner 1997
13 * \author Mathias Jansen
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 ***************************************************************/
44 #include <ogdf/basic/BinaryHeap.h>
45 #include <ogdf/graphalg/MinimumCut.h>
47 //used solely for efficiency and correctness checks of priority
55 MinCut::MinCut(Graph
&G
, EdgeArray
<double> &w
) : m_GC(G
) {
57 // Due to the node contraction (which destroys the Graph step by step),
58 // we have to create a GraphCopy.
59 //m_GC = new GraphCopy(G);
61 // Edge weights are initialized.
64 forall_edges(e
,m_GC
) {
65 m_w
[e
] = w
[(m_GC
).original(e
)];
67 m_contractedNodes
.init(m_GC
);
75 void MinCut::contraction(node t
, node s
) {
78 * The contraction of the two nodes \as and \a t is performed as follows:
79 * in the first step, all edges between \a s and \a t are deleted, and all edges incident
80 * to \a s are redirected to \a t. Then, node \a s is deleted and the adjacency list of \a t
81 * is checked for parallel edges. If k parallel edges are found, k-1 of them are deleted
82 * and their weights are added to the edge that is left.
85 // Step 1: redirecting edges and deleting node \a s
86 adjEntry adj
= s
->firstAdj();
89 adjEntry succ
= adj
->succ();
90 edge e
= adj
->theEdge();
91 if (e
->source() == t
|| e
->target() == t
) {
94 else if (e
->source() == s
) {
105 * Because of technical problems that occur when deleting edges and thus adjacency entries in a loop,
106 * a NodeArray is filled with the edges incident to node \a t.
107 * This NodeArray is checked for entries with more than one edge, which corresponds
111 // NodeArray containing parallel edges
112 NodeArray
<List
<edge
> > adjNodes(m_GC
);
115 adjNodes
[adj
->twinNode()].pushBack(adj
->theEdge());
118 // Step 2: deleting parallel edges and adding their weights
119 node v
= m_GC
.firstNode();
121 if (adjNodes
[v
].size() > 1) {
122 edge e
= adjNodes
[v
].front();
123 adjNodes
[v
].popFront();
124 ListConstIterator
<edge
> it
;
125 for (it
=adjNodes
[v
].begin(); it
.valid(); ++it
) {
127 // Add weight of current edge to \a e.
128 m_w
[e
] += m_w
[(*it
)];
137 double MinCut::minimumCutPhase() {
140 * This function computes the mincut of the current phase.
141 * First, nodes are added successively in descending order of the sum of
142 * their incident edge weights to the list \a markedNodes.
143 * Afterwards, the current mincut value \a cutOfThePhase is computed, which corresponds to the
144 * sum of the weights of those edges incident to node \a t, which is the node that has been
145 * added to list \a markedNodes at last.
146 * At the end, the two last added nodes (\a s and \a t) are contracted and the \cutOfThePhase
150 // Contains the mincut value according to the current phase.
151 double cutOfThePhase
;
153 List
<node
> markedNodes
;
154 List
<node
> leftoverNodes
;
156 // Contains for each node the sum of the edge weights of those edges
157 // incident to nodes in list \a markedNodes
158 NodeArray
<double> nodePrio(m_GC
);
160 BinaryHeap
<node
> pq(m_GC
.numberOfNodes());
161 NodeArray
<const BinaryHeap
<node
>::Element
*> pqEntry(m_GC
);
163 // The two nodes that have been added last to the list \a markedNodes.
164 // These are the two nodes that have to be contracted at the end of the function.
167 // Initialization of data structures
169 forall_nodes(v
,m_GC
) {
170 leftoverNodes
.pushBack(v
);
172 pqEntry
[v
] = &(pq
.insert(v
, 0.0));
175 nodePrio
.fill(0.0); //should do this in constructor init above
177 // The start-node can be chosen arbitrarily. It has no effect on the correctness of the algorithm.
178 // Here, always the first node in the list \a leftoverNodes is chosen.
179 v
= leftoverNodes
.popFrontRet(); markedNodes
.pushBack(v
);
181 //assumes that no multiedges exist
183 nodePrio
[adj
->twinNode()] = m_w
[adj
->theEdge()];
185 pq
.decPriority(*pqEntry
[adj
->twinNode()], -m_w
[adj
->theEdge()]);
189 // Temporary variables
190 ListIterator
<node
> it1
;
191 node maxWeightNode
; ListIterator
<node
> maxWeightNodeIt
;
192 //replaces line above
194 node maxWeightNodePq
;
198 // Successively adding the most tightly connected node.
199 while (markedNodes
.size() != m_GC
.numberOfNodes()) {
202 maxWeightNode
= NULL
;
204 //Find the most tightly connected node
205 maxWeightNodePq
= NULL
;
206 if (pq
.top()->getPriority() < mostTightly
)
208 mostTightly
= (maxWeightNodePq
= pq
.extractMin())->getPriority();
211 // The loop computing the most tightly connected node to the current set \a markedNodes.
212 // For better performance, this should be done using PriorityQueues! Since this algorithmn
213 // is only used for the Cut-separation within the Branch&Cut-algorithmn for MCPSP, only small
214 // and moderate Graph sizes are considered. Thus, the total running time is hardly affected.
215 for(it1
=leftoverNodes
.begin(); it1
.valid(); ++it1
) {
217 if(nodePrio
[(*it1
)] > mostTightly
) {
218 maxWeightNode
= (*it1
);
219 maxWeightNodeIt
= it1
;
220 mostTightly
= nodePrio
[(*it1
)];
224 OGDF_ASSERT(maxWeightNode
== maxWeightNodePq
);
227 // If the graph is not connected, maxWeightNode might not be updated in each iteration.
228 // Todo: Why not? Just because priority is zero? Then we can simplify this...
229 // Hence, in this case we simply choose one of the leftoverNodes (the first one).
230 if (maxWeightNode
== NULL
) {
231 maxWeightNode
= leftoverNodes
.front();
232 maxWeightNodeIt
= leftoverNodes
.begin();
235 // Adding \a maxWeightNode to the list \a markedNodes
236 markedNodes
.pushBack(maxWeightNode
);
238 // Deleting \a maxWeightNode from list \a leftoverNodes
239 leftoverNodes
.del(maxWeightNodeIt
);
241 // Updating the node priorities
243 forall_adj(a
,maxWeightNode
) {
244 nodePrio
[a
->twinNode()] += m_w
[a
->theEdge()];
247 //replaces loop above
248 forall_adj(a
, maxWeightNodePq
) {
249 //should have some decreasePriorityBy instead...
250 pq
.decPriority(*pqEntry
[a
->twinNode()],
251 pqEntry
[a
->twinNode()]->getPriority() - m_w
[a
->theEdge()]);
254 }// end of loop while(markedNodes.size()...)
256 // Computing value \a cutOfThePhase
258 ListConstIterator
<node
> last
= markedNodes
.rbegin();
259 t
= (*last
); s
= *(last
.pred());
261 forall_adj(t_adj
,t
) {
262 cutOfThePhase
+= m_w
[t_adj
->theEdge()];
265 // If the current \a cutOfThePhase is strictly smaller than the global mincut value,
266 // the partition defining the mincut has to be updated.
267 if(cutOfThePhase
< m_minCut
) {
269 m_partition
.pushBack(m_GC
.original(t
));
270 for(ListConstIterator
<node
> it
= m_contractedNodes
[t
].begin(); it
.valid(); ++it
) {
271 m_partition
.pushBack(*it
);
275 // Since nodes in \a m_GC correspond to sets of nodes (due to the node contraction),
276 // the NodeArray \a m_contractedNodes has to be updated.
277 m_contractedNodes
[t
].pushBack(m_GC
.original(s
));
278 ListConstIterator
<node
> contractIt
;
279 for (contractIt
= m_contractedNodes
[s
].begin(); contractIt
.valid(); ++contractIt
) {
280 m_contractedNodes
[t
].pushBack((*contractIt
));
283 // Performing the node contraction of nodes \a s and \a t.
286 return cutOfThePhase
;
290 double MinCut::minimumCut() {
293 * Main loop of the algorithm
294 * As long as GraphCopy \a m_GC contains at least two nodes,
295 * function minimumCutPhase() is invoked and \a m_minCut is updated
298 for (int i
=m_GC
.numberOfNodes(); i
>1; --i
) {
299 m_minCut
= min(m_minCut
,minimumCutPhase());
300 if (m_minCut
== 0.0) return m_minCut
;
306 void MinCut::partition(List
<node
> &nodes
) {
309 ListConstIterator
<node
> it
;
310 for (it
=m_partition
.begin(); it
.valid(); ++it
) {
316 void MinCut::cutEdges(List
<edge
> &edges
, Graph
&G
) {
319 NodeArray
<bool> inPartition(G
);
320 inPartition
.fill(false);
321 ListConstIterator
<node
> nodeIt
;
323 for (nodeIt
=m_partition
.begin(); nodeIt
.valid(); ++nodeIt
) {
324 inPartition
[*nodeIt
] = true;
327 for (nodeIt
=m_partition
.begin(); nodeIt
.valid(); ++nodeIt
) {
329 forall_adj_edges(e
,(*nodeIt
)) {
330 if(e
->source() == (*nodeIt
)) {
331 if(inPartition
[e
->target()] == false) {
335 if(inPartition
[e
->source()] == false) {