1
2
3
4
5
6
7
8
9
10 package edu.uci.ics.jung.algorithms.flows;
11
12 import java.util.ArrayList;
13 import java.util.Collection;
14 import java.util.HashMap;
15 import java.util.HashSet;
16 import java.util.List;
17 import java.util.Map;
18 import java.util.Set;
19
20 import org.apache.commons.collections15.Buffer;
21 import org.apache.commons.collections15.Factory;
22 import org.apache.commons.collections15.Transformer;
23 import org.apache.commons.collections15.buffer.UnboundedFifoBuffer;
24
25 import edu.uci.ics.jung.algorithms.util.IterativeProcess;
26 import edu.uci.ics.jung.graph.DirectedGraph;
27 import edu.uci.ics.jung.graph.util.EdgeType;
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48 public class EdmondsKarpMaxFlow<V,E> extends IterativeProcess {
49
50 private DirectedGraph<V,E> mFlowGraph;
51 private DirectedGraph<V,E> mOriginalGraph;
52 private V source;
53 private V target;
54 private int mMaxFlow;
55 private Set<V> mSourcePartitionNodes;
56 private Set<V> mSinkPartitionNodes;
57 private Set<E> mMinCutEdges;
58
59 private Map<E,Number> residualCapacityMap = new HashMap<E,Number>();
60 private Map<V,V> parentMap = new HashMap<V,V>();
61 private Map<V,Number> parentCapacityMap = new HashMap<V,Number>();
62 private Transformer<E,Number> edgeCapacityTransformer;
63 private Map<E,Number> edgeFlowMap;
64 private Factory<E> edgeFactory;
65
66
67
68
69
70
71
72
73
74
75
76
77 @SuppressWarnings("unchecked")
78 public EdmondsKarpMaxFlow(DirectedGraph<V,E> directedGraph, V source, V sink,
79 Transformer<E,Number> edgeCapacityTransformer, Map<E,Number> edgeFlowMap,
80 Factory<E> edgeFactory) {
81
82 if(directedGraph.getVertices().contains(source) == false ||
83 directedGraph.getVertices().contains(sink) == false) {
84 throw new IllegalArgumentException("source and sink vertices must be elements of the specified graph");
85 }
86 if (source.equals(sink)) {
87 throw new IllegalArgumentException("source and sink vertices must be distinct");
88 }
89 mOriginalGraph = directedGraph;
90
91 this.source = source;
92 this.target = sink;
93 this.edgeFlowMap = edgeFlowMap;
94 this.edgeCapacityTransformer = edgeCapacityTransformer;
95 this.edgeFactory = edgeFactory;
96 try {
97 mFlowGraph = directedGraph.getClass().newInstance();
98 for(E e : mOriginalGraph.getEdges()) {
99 mFlowGraph.addEdge(e, mOriginalGraph.getSource(e),
100 mOriginalGraph.getDest(e), EdgeType.DIRECTED);
101 }
102 for(V v : mOriginalGraph.getVertices()) {
103 mFlowGraph.addVertex(v);
104 }
105
106 } catch (InstantiationException e) {
107 e.printStackTrace();
108 } catch (IllegalAccessException e) {
109 e.printStackTrace();
110 }
111 mMaxFlow = 0;
112 mSinkPartitionNodes = new HashSet<V>();
113 mSourcePartitionNodes = new HashSet<V>();
114 mMinCutEdges = new HashSet<E>();
115 }
116
117 private void clearParentValues() {
118 parentMap.clear();
119 parentCapacityMap.clear();
120 parentCapacityMap.put(source, Integer.MAX_VALUE);
121 parentMap.put(source, source);
122 }
123
124 protected boolean hasAugmentingPath() {
125
126 mSinkPartitionNodes.clear();
127 mSourcePartitionNodes.clear();
128 mSinkPartitionNodes.addAll(mFlowGraph.getVertices());
129
130 Set<E> visitedEdgesMap = new HashSet<E>();
131 Buffer<V> queue = new UnboundedFifoBuffer<V>();
132 queue.add(source);
133
134 while (!queue.isEmpty()) {
135 V currentVertex = queue.remove();
136 mSinkPartitionNodes.remove(currentVertex);
137 mSourcePartitionNodes.add(currentVertex);
138 Number currentCapacity = parentCapacityMap.get(currentVertex);
139
140 Collection<E> neighboringEdges = mFlowGraph.getOutEdges(currentVertex);
141
142 for (E neighboringEdge : neighboringEdges) {
143
144 V neighboringVertex = mFlowGraph.getDest(neighboringEdge);
145
146 Number residualCapacity = residualCapacityMap.get(neighboringEdge);
147 if (residualCapacity.intValue() <= 0 || visitedEdgesMap.contains(neighboringEdge))
148 continue;
149
150 V neighborsParent = parentMap.get(neighboringVertex);
151 Number neighborCapacity = parentCapacityMap.get(neighboringVertex);
152 int newCapacity = Math.min(residualCapacity.intValue(),currentCapacity.intValue());
153
154 if ((neighborsParent == null) || newCapacity > neighborCapacity.intValue()) {
155 parentMap.put(neighboringVertex, currentVertex);
156 parentCapacityMap.put(neighboringVertex, new Integer(newCapacity));
157 visitedEdgesMap.add(neighboringEdge);
158 if (neighboringVertex != target) {
159 queue.add(neighboringVertex);
160 }
161 }
162 }
163 }
164
165 boolean hasAugmentingPath = false;
166 Number targetsParentCapacity = parentCapacityMap.get(target);
167 if (targetsParentCapacity != null && targetsParentCapacity.intValue() > 0) {
168 updateResidualCapacities();
169 hasAugmentingPath = true;
170 }
171 clearParentValues();
172 return hasAugmentingPath;
173 }
174
175 @Override
176 public void step() {
177 while (hasAugmentingPath()) {
178 }
179 computeMinCut();
180
181 }
182
183 private void computeMinCut() {
184
185 for (E e : mOriginalGraph.getEdges()) {
186
187 V source = mOriginalGraph.getSource(e);
188 V destination = mOriginalGraph.getDest(e);
189 if (mSinkPartitionNodes.contains(source) && mSinkPartitionNodes.contains(destination)) {
190 continue;
191 }
192 if (mSourcePartitionNodes.contains(source) && mSourcePartitionNodes.contains(destination)) {
193 continue;
194 }
195 if (mSinkPartitionNodes.contains(source) && mSourcePartitionNodes.contains(destination)) {
196 continue;
197 }
198 mMinCutEdges.add(e);
199 }
200 }
201
202
203
204
205 public int getMaxFlow() {
206 return mMaxFlow;
207 }
208
209
210
211
212
213 public Set<V> getNodesInSinkPartition() {
214 return mSinkPartitionNodes;
215 }
216
217
218
219
220
221 public Set<V> getNodesInSourcePartition() {
222 return mSourcePartitionNodes;
223 }
224
225
226
227
228 public Set<E> getMinCutEdges() {
229 return mMinCutEdges;
230 }
231
232
233
234
235 public DirectedGraph<V,E> getFlowGraph() {
236 return mFlowGraph;
237 }
238
239 @Override
240 protected void initializeIterations() {
241 parentCapacityMap.put(source, Integer.MAX_VALUE);
242 parentMap.put(source, source);
243
244 List<E> edgeList = new ArrayList<E>(mFlowGraph.getEdges());
245
246 for (int eIdx=0;eIdx< edgeList.size();eIdx++) {
247 E edge = edgeList.get(eIdx);
248 Number capacity = edgeCapacityTransformer.transform(edge);
249
250 if (capacity == null) {
251 throw new IllegalArgumentException("Edge capacities must be provided in Transformer passed to constructor");
252 }
253 residualCapacityMap.put(edge, capacity);
254
255 V source = mFlowGraph.getSource(edge);
256 V destination = mFlowGraph.getDest(edge);
257
258 if(mFlowGraph.isPredecessor(source, destination) == false) {
259 E backEdge = edgeFactory.create();
260 mFlowGraph.addEdge(backEdge, destination, source, EdgeType.DIRECTED);
261 residualCapacityMap.put(backEdge, 0);
262 }
263 }
264 }
265
266 @Override
267 protected void finalizeIterations() {
268
269 for (E currentEdge : mFlowGraph.getEdges()) {
270 Number capacity = edgeCapacityTransformer.transform(currentEdge);
271
272 Number residualCapacity = residualCapacityMap.get(currentEdge);
273 if (capacity != null) {
274 Integer flowValue = new Integer(capacity.intValue()-residualCapacity.intValue());
275 this.edgeFlowMap.put(currentEdge, flowValue);
276 }
277 }
278
279 Set<E> backEdges = new HashSet<E>();
280 for (E currentEdge: mFlowGraph.getEdges()) {
281
282 if (edgeCapacityTransformer.transform(currentEdge) == null) {
283 backEdges.add(currentEdge);
284 } else {
285 residualCapacityMap.remove(currentEdge);
286 }
287 }
288 for(E e : backEdges) {
289 mFlowGraph.removeEdge(e);
290 }
291 }
292
293 private void updateResidualCapacities() {
294
295 Number augmentingPathCapacity = parentCapacityMap.get(target);
296 mMaxFlow += augmentingPathCapacity.intValue();
297 V currentVertex = target;
298 V parentVertex = null;
299 while ((parentVertex = parentMap.get(currentVertex)) != currentVertex) {
300 E currentEdge = mFlowGraph.findEdge(parentVertex, currentVertex);
301
302 Number residualCapacity = residualCapacityMap.get(currentEdge);
303
304 residualCapacity = residualCapacity.intValue() - augmentingPathCapacity.intValue();
305 residualCapacityMap.put(currentEdge, residualCapacity);
306
307 E backEdge = mFlowGraph.findEdge(currentVertex, parentVertex);
308 residualCapacity = residualCapacityMap.get(backEdge);
309 residualCapacity = residualCapacity.intValue() + augmentingPathCapacity.intValue();
310 residualCapacityMap.put(backEdge, residualCapacity);
311 currentVertex = parentVertex;
312 }
313 }
314 }