/* ==========================================
* JGraphT : a free Java graph-theory library
* ==========================================
*
* Project Info: http://jgrapht.sourceforge.net/
* Project Creator: Barak Naveh (http://sourceforge.net/users/barak_naveh)
*
* (C) Copyright 2003-2012, by Barak Naveh and Contributors.
*
* This program and the accompanying materials are dual-licensed under
* either
*
* (a) the terms of the GNU Lesser General Public License version 2.1
* as published by the Free Software Foundation, or (at your option) any
* later version.
*
* or (per the licensee's choosing)
*
* (b) the terms of the Eclipse Public License v1.0 as published by
* the Eclipse Foundation.
*/
/* -------------------------
* MinSourceSinkCut.java
* -------------------------
* (C) Copyright 2012-2012, by Joris Kinable and Contributors.
*
* Original Author: Joris Kinable
* Contributor(s):
*
* Changes
* -------
* 26-Nov-2012 : Initial revision (JK);
*
*/
package org.jgrapht.alg;
import java.util.*;
import org.jgrapht.*;
/**
* Given a directed, weighted graph G(V,E). This class computes a minimum s-t
* cut. For this, it relies on the EdmondsKarpMaximumFlow implementation. Note:
* it is not recommended to use this class to calculate the overall minimum cut
* in a graph by iteratively invoking this class for all source-sink pairs. This
* is computationally expensive. Instead, use the StoerWagnerMinimumCut
* implementation.
*
* @author Joris Kinable
*/
public class MinSourceSinkCut<V, E>
{
EdmondsKarpMaximumFlow<V, E> ekMaxFlow;
Set<V> minCut = null;
DirectedGraph<V, E> graph;
double cutWeight;
V source = null;
V sink = null;
double epsilon = EdmondsKarpMaximumFlow.DEFAULT_EPSILON;
public MinSourceSinkCut(DirectedGraph<V, E> graph)
{
this.ekMaxFlow = new EdmondsKarpMaximumFlow<V, E>(graph);
this.graph = graph;
}
public MinSourceSinkCut(DirectedGraph<V, E> graph, double epsilon)
{
this.ekMaxFlow = new EdmondsKarpMaximumFlow<V, E>(graph);
this.graph = graph;
this.epsilon = epsilon;
}
/**
* Compute a minimum s-t cut
*
* @param source
* @param sink
*/
public void computeMinCut(V source, V sink)
{
this.source = source;
this.sink = sink;
minCut = new HashSet<V>();
//First compute a maxFlow from source to sink
ekMaxFlow.calculateMaximumFlow(source, sink);
this.cutWeight = ekMaxFlow.getMaximumFlowValue();
Map<E, Double> maxFlow = ekMaxFlow.getMaximumFlow();
Queue<V> processQueue = new LinkedList<V>();
processQueue.add(source);
while (!processQueue.isEmpty()) {
V vertex = processQueue.remove();
if (minCut.contains(vertex)) {
continue;
} else {
minCut.add(vertex);
}
//1. Get the forward edges with residual capacity
Set<E> outEdges = new HashSet<E>(graph.outgoingEdgesOf(vertex));
for (Iterator<E> it = outEdges.iterator(); it.hasNext();) {
E edge = it.next();
double edgeCapacity = graph.getEdgeWeight(edge);
double flowValue = maxFlow.get(edge);
if (Math.abs(edgeCapacity - flowValue) <= epsilon) { //No residual capacity on the edge
it.remove();
}
}
for (E edge : outEdges) {
processQueue.add(Graphs.getOppositeVertex(graph, edge, vertex));
}
//2. Get the backward edges with non-zero flow
Set<E> inEdges = new HashSet<E>(graph.incomingEdgesOf(vertex));
for (Iterator<E> it = inEdges.iterator(); it.hasNext();) {
E edge = it.next();
//double edgeCapacity=graph.getEdgeWeight(edge);
double flowValue = maxFlow.get(edge);
if (flowValue <= epsilon) { //There is no flow on this edge
it.remove();
}
}
for (E edge : inEdges) {
processQueue.add(Graphs.getOppositeVertex(graph, edge, vertex));
}
}
}
/**
* @return Returns the min cut partition containing the source, or null if
* there was no call to computeMinCut(V source, V sink)
*/
public Set<V> getSourcePartition()
{
return Collections.unmodifiableSet(minCut);
}
/**
* Returns the min cut partition containing the sink
*
* @return returns the min cut partition containing the sink
*/
public Set<V> getSinkPartition()
{
if (minCut == null) {
return null;
}
Set<V> set = new HashSet<V>(graph.vertexSet());
set.removeAll(minCut);
return Collections.unmodifiableSet(set);
}
/**
* Get the cut weight. This is equal to the max s-t flow
*
* @return cut weight
*/
public double getCutWeight()
{
return cutWeight;
}
/**
* Let S be the set containing the source, and T be the set containing the
* sink, i.e. T=V\S. This method returns the edges which have their tail in
* S, and their head in T
*
* @return all edges which have their tail in S, and their head in T. If
* computeMinCut(V source, V sink) has not been invoked, this method returns
* null.
*/
public Set<E> getCutEdges()
{
if (minCut == null) {
return null;
}
Set<E> cutEdges = new HashSet<E>();
for (V vertex : minCut) {
for (E edge : graph.outgoingEdgesOf(vertex)) {
if (!minCut.contains(
Graphs.getOppositeVertex(graph, edge, vertex)))
{
cutEdges.add(edge);
}
}
}
return Collections.unmodifiableSet(cutEdges);
}
/**
* Returns the source of the last call
*
* @return source of last minCut call, null if there was no call
*/
public V getCurrentSource()
{
return source;
}
/**
* Returns the sink of the last call
*
* @return sink of last minCut call, null if there was no call
*/
public V getCurrentSink()
{
return sink;
}
}
// End MinSourceSinkCut.java