AuD
Lecture 'Algorithmen und Datenstrukturen' (code examples)
MaxFlowExample.java
Go to the documentation of this file.
1package aud.example.graph;
2
3import java.io.File;
4
5import aud.*;
6import aud.graph.matrix.*;
7import aud.util.DotViewer;
9
21public class MaxFlowExample extends SingleStepper {
22
24 double widthfactor = 3.0;
25
26 protected DotViewer viewer_ = DotViewer.displayWindow
27 ((String) null,"aud.example.graph.MaxFlowExample");
28
29 @Override protected void onHalt() {
30 viewer_.display(g_);
31 }
32
34 public MaxFlowExample() {
35 super("aud.example.graph.MaxFlowExample");
36 }
37
39 MyGraph g_ = null;
40
42 MyNode s_ = null;
43
45 MyNode t_ = null;
46
48 SparseMatrix<Double> flow_ = null;
49
51 double getFlow(MyNode i,MyNode j) {
52 return flow_.get(i.index(),j.index());
53 }
55 void setFlow(MyNode i,MyNode j,double f) {
56 flow_.set(i.index(),j.index(),f);
57 }
58
60 public void computeMaxFlow(MyGraph g) {
61 initialize(g);
62
63 double cp;
64
65 while (!Double.isInfinite(cp=findAugmentingPath())) {
66 addPath(cp);
67 }
68
69 cleanup();
70 }
71
78 double findAugmentingPath() {
79
80 for (MyNode n : g_) {
81 n.p=null;
82 n.d=Double.POSITIVE_INFINITY; // measure capacity of path
83 }
85 open.enqueue(s_);
86 s_.p=s_; // mark as visited
87
88 while (!open.is_empty()) {
89 MyNode u=open.dequeue();
90
91 if (u==t_)
92 break;
93
94 for (MyEdge e : g_.getOutEdges(u)) {
95 MyNode v=(MyNode) e.destination();
96
97 double capacity=e.getWeight();
98 double residual=capacity-getFlow(u,v);
99
100 if (v.p==null && residual>0.0) {
101 v.p=u;
102 v.d=(u.d<=residual ? u.d : residual); // adjust capacity of path
103
104 open.enqueue(v);
105 }
106 }
107 }
108 s_.p=null;
109
110 assert((t_.p==null && Double.isInfinite(t_.d)) ||
111 (t_.p!=null && !Double.isInfinite(t_.d)));
112
113 return t_.d;
114 }
115
117 void addPath(double cp) {
118 assert(t_.p!=null && !Double.isInfinite(t_.d));
119 assert(t_.d==cp);
120
121 MyNode v=t_,u=t_.p;
122
123 do {
124 MyEdge fe=g_.getEdge(u,v);
125 MyEdge be=g_.getEdge(v,u);
126
127 if (be==null) {
128 be=g_.addEdge(v,u);
129 be.setWeight(0.0); // flow along back edge may be allowed even though!
130 be.color=BACKEDGE;
131 }
132
133 double f=getFlow(u,v);
134
135 assert(getFlow(v,u)==-f);
136
137 f+=cp;
138
139 setFlow(u,v, f);
140 setFlow(v,u,-f);
141
142
143 fe.penwidth=cp*widthfactor;
144 fe.setLabel(""+f+"/"+fe.getWeight());
145 be.setLabel(""+(-f)+"/"+be.getWeight());
146
147 System.err.println(u);
148
149 v=u;
150 u=u.p;
151 } while (u!=null);
152
153 halt("add path with capacity "+cp);
154 }
155
156 static final String BACKEDGE = "red";
157
159 void initialize(MyGraph g) {
160 if (!g.isDirected())
161 throw new RuntimeException("expect directed graph!");
162
163 g_=g;
164 s_=findSource(g);
165 t_=findSink(g);
166
167 halt("Compute max flow from "+s_.getLabel()+" to "+t_.getLabel());
168
169 // initialize zero flow
170 flow_=new SparseMatrix<Double>();
171
172 for (MyEdge e : g.edges()) {
173 MyNode s=(MyNode) e.source(), t=(MyNode) e.destination();
174 setFlow(s,t,0.0);
175 }
176 }
177
179 void cleanup() {
180 Vector<MyEdge> backward_edges=new Vector<MyEdge>();
181
182 for (MyEdge e : g_.edges()) {
183 if (e.getWeight()==0.0) {
184 assert(e.color==BACKEDGE);
185 backward_edges.push_back(e);
186 }
187 else {
188 double f=getFlow((MyNode) e.source(),(MyNode) e.destination());
189 e.penwidth=(f>0.0 ? f*widthfactor : -1.0);
190 e.color=(f>0.0 ? "blue" : null);
191 }
192 }
193
194 for (MyEdge e : backward_edges)
195 g_.removeEdge(e);
196
197 double f=0.0;
198 for (MyEdge e : g_.getOutEdges(s_))
199 f+=getFlow(s_,(MyNode) e.destination());
200
201 halt("RESULT with max flow = "+f);
202 }
203
205 MyNode findSource(MyGraph g) {
206 MyNode s=null;
207 for (MyNode n : g)
208 if (g.getInDegree(n)==0) {
209 if (s!=null)
210 throw new RuntimeException("not implemented: multiple sources!");
211 s=n;
212 }
213 if (s==null)
214 throw new RuntimeException("no source node found");
215 return s;
216 }
218 MyNode findSink(MyGraph g) {
219 MyNode s=null;
220 for (MyNode n : g)
221 if (g.getOutDegree(n)==0) {
222 if (s!=null)
223 throw new RuntimeException("not implemented: multiple sinks!");
224 s=n;
225 }
226 if (s==null)
227 throw new RuntimeException("no sink node found");
228 return s;
229 }
230
231 protected static void usage() {
232 System.err.println(
233 "java aud.example.graph.MaxFlowExample "+
234 "[-g graphfile] [-w factor]");
235 System.exit(-1);
236 }
237
239 protected static MyGraph createGraph() {
240 MyGraph g=new MyGraph(true);
241 MyNode s=g.addNode(), t=g.addNode(), a=g.addNode(), b=g.addNode();
242 s.setLabel("s");
243 t.setLabel("t");
244 s.setPosition(0.0,0.0);
245 t.setPosition(4.0,0.0);
246 a.setPosition(2.0,2.0);
247 b.setPosition(2.0,-2.0);
248 g.addEdge(s,a).setWeight(4.0);
249 g.addEdge(s,b).setWeight(2.0);
250 g.addEdge(a,b).setWeight(3.0);
251 g.addEdge(a,t).setWeight(1.0);
252 g.addEdge(b,t).setWeight(6.0);
253 return g;
254 }
255
257 public static void main(String[] args) {
258 MyGraph g=new MyGraph(true);
259
260 File graph=null;
261 double widthfactor=2.0; // emphasize pen width for visualization
262
263 for (int i=0;i<args.length;++i) {
264 if (args[i].compareTo("-g")==0)
265 graph=new File(args[++i]);
266 if (args[i].compareTo("-w")==0)
267 widthfactor=Double.parseDouble(args[++i]);
268 }
269
271 app.widthfactor=widthfactor;
272
273 if (graph==null)
274 g=createGraph();
275 else {
276 new GraphParser(g.getAbstractGraph()).parse(graph);
277 }
278
279 // compute max-flow
280 app.computeMaxFlow(g);
281 app.halt("DONE");
282
283 System.exit(0);
284 }
285
286}
Implementation of AbstractQueue as a (dynamically resized) circular buffer based on array.
Definition: Queue.java:11
void enqueue(T x)
Enqueue element at end of queue.
Definition: Queue.java:62
boolean is_empty()
Is queue empty?
Definition: Queue.java:35
T dequeue()
Remove front element from queue.
Definition: Queue.java:50
Implementation of an array-based vector.
Definition: Vector.java:44
void push_back(T obj)
insert new entry obj at the end [O(1) for sufficient capacity]
Definition: Vector.java:155
Parse text to build graph.
void parse(String input)
parse input
Example for computing the maximum flow using a Ford-Fulkerson type algorithm.
static void main(String[] args)
example (see also usage)
static MyGraph createGraph()
create a small example graph
MaxFlowExample()
create application
void computeMaxFlow(MyGraph g)
main algorithm (calls findAugmentingPath and addPath
graph based on aud.graph.GraphAM
Definition: MyGraph.java:11
AbstractGraph< AbstractNode, AbstractEdge > getAbstractGraph()
view this graph as an AbstractGraph
Definition: MyGraph.java:29
node with all possible attributes that we require ;-)
Definition: MyNode.java:6
MyNode p
node from which node was reached (defines spanning tree)
Definition: MyNode.java:16
String color
color as string
Definition: MyNode.java:27
double d
distance to start node (sum of weighs or edge count if no weights defined)
Definition: MyNode.java:21
int index()
get index, i.e., unique integer id within graph
Edge addEdge(Node source, Node destination)
Definition: GraphAM.java:49
String getLabel()
get text description
Definition: SimpleNode.java:12
void setLabel(String label)
set label (default label if label==null)
Definition: SimpleNode.java:16
void setPosition(double x, double y)
helper for drawing the graph (if supported)
Definition: SimpleNode.java:18
T get(int i, int j)
get entry (i,j) [O(log(nnz))]
Simple sparse matrix data structure.
T set(int i, int j, T data)
Set entry (i,j) to data [O(log(nnz))].
Simple viewer for Graphvizable.
Definition: DotViewer.java:47
void display(String code)
display dot code
Definition: DotViewer.java:107
Simple framework for single stepping code.
void halt()
wait for user
void halt(String text, int timeout)
display text and wait for user or timeout
sparse matrices for encoding adjacency
Definition: Coordinate.java:1
Graph data structures and algorithms.
utilities (not related to AuD lecture)
Definition: Colormap.java:1
AuD lecture: Data structures, algorithms, examples.
Definition: A234Tree.java:1