1 00:00:03,540 --> 00:00:08,983 Next, we're going to look at Java code for solving the max flow problem. 2 00:00:09,213 --> 00:00:14,476 This is the most complex. Graph processing algorithm we have seen so 3 00:00:14,476 --> 00:00:21,324 far but it's relatively a small amount of curve that builds upon the mechanisms that 4 00:00:21,557 --> 00:00:25,760 we have been studying for the last couple of lectures. 5 00:00:25,993 --> 00:00:33,075 So now, the graph that we are working with little more complicated because we have to 6 00:00:33,075 --> 00:00:37,900 associate with each edge not just the capacity but also a flow. 7 00:00:37,900 --> 00:00:43,623 So, we'll build a slightly more complicated data type for edges called a 8 00:00:43,623 --> 00:00:47,744 flow edge. Where, for each edge, we can keep track of 9 00:00:47,744 --> 00:00:52,094 that information. So, we not only have to keep the from 10 00:00:52,094 --> 00:00:57,817 vertex V and the to vertex W. The weight or the capacity C, associated 11 00:00:57,817 --> 00:01:02,320 with the edge but, and also the flow cuz that's a flow edge. 12 00:01:02,320 --> 00:01:07,892 And then the flow network. Since we're going to go through edges in 13 00:01:07,892 --> 00:01:13,922 the wrong direction we're going to have to put every flow edge, kind of like an 14 00:01:13,922 --> 00:01:20,358 undirected graph in both adjacency lists. And then we're going to test whether we're 15 00:01:20,358 --> 00:01:24,372 going, which direction we're going through an edge. 16 00:01:24,372 --> 00:01:27,905 It's kind of like using an undirected graph. 17 00:01:28,226 --> 00:01:34,569 But the flow network, anyway, has to have edges in both places so it can do backward 18 00:01:34,569 --> 00:00:58,764 edges. A simple way to arrange for this is to 19 00:01:38,181 --> 00:01:44,524 compute for the edges what's called the residual capacity, and that's just what 20 00:01:44,524 --> 00:01:49,585 we're going to use to compute the bottleneck value, the only max amount of 21 00:01:49,585 --> 00:01:54,481 flow we can pull through. So for the backward edge, we'll assign the 22 00:01:54,481 --> 00:01:59,784 residualCapacityTo be the amount of flow. And for the forward edge, it'll be the 23 00:01:59,784 --> 00:02:04,204 capacity minus the flow. So, that's the maximum amount of stuff we 24 00:02:04,204 --> 00:02:09,778 can get through the edge when we're augmenting its residual capacity. so and 25 00:02:09,778 --> 00:02:15,650 to actually do the augmentation, you will have a value which is your maximum that 26 00:02:15,650 --> 00:02:20,258 you're going to, that you're going to augment and so if you are on the forward 27 00:02:20,258 --> 00:02:25,090 edge, you add it and if you're on a backward edge, you subtract it. 28 00:02:25,292 --> 00:02:30,080 And so, that's the basic idea and its just quite natural from the graph 29 00:02:30,080 --> 00:02:35,542 representation we've been using and the way that the codes focus on how algorithm 30 00:02:35,542 --> 00:02:40,810 woks. So one way to think of this is to little 31 00:02:40,810 --> 00:02:49,097 bit closer to the representation that we're using, is to consider what's called 32 00:02:49,097 --> 00:02:57,870 a residual network that for every edge every forward edge in the network, it has 33 00:02:57,870 --> 00:03:04,906 the, the in, forward edge going that has the amount of flow left and a backward 34 00:03:04,906 --> 00:03:13,314 edge with the amount of flow that's there. And if you have a, a full forward edge, or 35 00:03:13,314 --> 00:03:18,980 a, or an empty backward edge then you only have one such. 36 00:03:18,980 --> 00:03:25,878 So this an example of the residual network for this amount of flow. 37 00:03:26,074 --> 00:03:31,420 You can't put any more flow through from this vertex to this vertex, so there's no 38 00:03:31,420 --> 00:03:35,202 edge going that way. But you can remove four units of flow 39 00:03:35,202 --> 00:03:38,723 going that way. So, that's because of the backward edge. 40 00:03:38,919 --> 00:03:42,244 So and in this case we have a full forward edge. 41 00:03:42,244 --> 00:03:47,134 So, there's no edge going this way, cuz we can't put any more flow through. 42 00:03:47,330 --> 00:03:52,285 But there's nine going that way, That's another example of a full forward 43 00:03:52,285 --> 00:03:55,910 edge. This empty one you can put eight units of 44 00:03:55,910 --> 00:04:00,972 flow that way, so we have an edge in the residual network going that way. 45 00:04:01,183 --> 00:04:06,456 But no way to go that way, because there's no flow, there's no backward edge. 46 00:04:06,456 --> 00:04:12,843 And so this network is just a natural way to look at the network while the flow is 47 00:04:12,843 --> 00:04:17,887 being computed cause it's a digraph that we're going to search to find the 48 00:04:17,887 --> 00:04:21,951 augmenting path. If a directed path in this network that's 49 00:04:21,951 --> 00:04:28,327 from s to t, that's an augmenting path. And that's a simple mechanism that helps 50 00:04:28,327 --> 00:04:33,407 us write compact and elegant code. So that's an augmenting path in the 51 00:04:33,407 --> 00:04:39,286 original network and that just turns out to be a directed path in the residual 52 00:04:39,286 --> 00:04:42,537 network. So then, we can just use our algorithms 53 00:04:42,537 --> 00:04:48,140 that we've already studied for finding directed paths in the residual network. 54 00:04:48,140 --> 00:04:55,155 Alright, so here's the API for flow edges. And they just have the few extra methods 55 00:04:55,387 --> 00:05:01,786 to allow us to compute and make decisions based on the amount of flow and capacity 56 00:05:01,786 --> 00:05:06,257 in the edge. These are the computations that we need to 57 00:05:06,257 --> 00:05:12,194 implement the forward focus in algorithm. So every edge has a from and a to. 58 00:05:12,194 --> 00:05:18,670 If you have one point, it gives you the other one which we need just as we did in 59 00:05:18,670 --> 00:05:22,796 undirected graphs. Every edge has capacity and a flow and a 60 00:05:22,796 --> 00:05:28,332 residual capacity, which we compute from a capacity in flow, then we want to be an 61 00:05:28,332 --> 00:05:34,244 addResidualFlow to any edge, and its added and if its forward, and it gets subtracted 62 00:05:34,244 --> 00:05:39,892 if it's forward. So those are the basic methods in the API 63 00:05:39,892 --> 00:05:45,655 for a flow edge and, and the implementation of all of them is 64 00:05:45,655 --> 00:05:51,773 straightforward. So notice that one thing that's a little 65 00:05:51,773 --> 00:05:57,845 different from many othe, you know, classes is that actually the goal of our 66 00:05:57,845 --> 00:06:00,966 computation is to fill in these values flow. 67 00:06:00,966 --> 00:06:05,266 So, they're not final variables that's what we're computing. 68 00:06:05,474 --> 00:06:10,259 Now. we do it through addResidualFlow but still it's not a final. 69 00:06:10,467 --> 00:06:16,085 So, create an edge, just with a V to W given capacity, just fill in the instance 70 00:06:16,085 --> 00:06:19,900 variables and all these other ones are just getters. 71 00:06:20,108 --> 00:06:25,379 Others just like in an undirected graph. And then, residualCapacity and 72 00:06:25,379 --> 00:06:28,500 addResidualFlow are also easy to implement. 73 00:06:28,500 --> 00:06:33,937 So, residualCapacity if it's on the from edge, you return the flow, if it's on the 74 00:06:33,937 --> 00:06:38,703 to edge or it's the backward edge, you return capacity minus flow, just as we 75 00:06:38,703 --> 00:06:41,993 said. And addResidualFlow makes the same test to 76 00:06:41,993 --> 00:06:44,880 decide whether to add or subtract the flow. 77 00:06:44,880 --> 00:06:52,251 So very simple implementations of all those operations for our flow edges in a 78 00:06:52,251 --> 00:06:57,214 flow network. So, what about the floor network, API? 79 00:06:57,537 --> 00:07:05,072 it's again going to be our standard API, just that floor graph, flow networks are 80 00:07:05,072 --> 00:07:11,903 built from flow edges. And they're going to be built for the 81 00:07:11,903 --> 00:07:17,459 client which is going to be the max flow algorithm. it's going to have a method 82 00:07:17,459 --> 00:07:23,082 that gives an interval for every vertex of all the forward and backward edges instant 83 00:07:23,082 --> 00:07:27,920 on that vertex and sh, so that client is going to use these basic things. 84 00:07:27,920 --> 00:07:34,286 And given everything we've seen this implementation is pretty straightforward. 85 00:07:34,286 --> 00:07:40,330 It's pretty much just like edge-weighted graph, except we use low edges now. 86 00:07:40,652 --> 00:02:35,484 And then, when we add an edge even though it's kind of a directed network to handle 87 00:07:47,018 --> 00:07:53,304 flow and forward and backward edges, We add every edge to both adjacency lists. 88 00:07:53,626 --> 00:07:58,220 But simple code, quite similar to what we've seen before. 89 00:07:58,563 --> 00:08:04,510 So we'll, again network is usually huge and sparse. 90 00:08:04,510 --> 00:08:10,857 So, we use a vertex index array and each entry associated with each vertex will 91 00:08:10,857 --> 00:08:17,364 contain references to all the edges that are incident on that vertex whether 92 00:08:17,364 --> 00:08:22,747 they're forward or backwards. So, just like an un-directed graph, you 93 00:08:22,747 --> 00:08:26,764 might have to, you'll have two references to the same edge. 94 00:08:26,764 --> 00:08:33,955 One and it's a from and the other and it's to and then rather than just to wait, they 95 00:08:33,955 --> 00:08:39,236 have a flow and a capacity. So from zero to two, it's got capacity 96 00:08:39,236 --> 00:08:44,436 three and one unit of flow in it. So, that's an example of, of how to 97 00:08:44,436 --> 00:08:48,985 represent that edge. So, flow network has got flows in it, 98 00:08:48,985 --> 00:08:53,616 that's the grey and it's got capacities, and that's the white. 99 00:08:53,616 --> 00:08:59,710 And otherwise, it's kind of similar to our undirected graph representation. 100 00:08:59,710 --> 00:09:03,674 I've got one more processing, the,, processing the graph. 101 00:09:03,674 --> 00:09:10,306 We use residualCapacity to make that kind of work in the residual path in natural 102 00:09:10,306 --> 00:09:13,478 way. So, this is the implementation of the 103 00:09:13,478 --> 00:09:18,145 forward focus in algorithm. And again h, pretty straightforward to 104 00:09:18,576 --> 00:09:24,239 given the description that we've done, and the graph processing code that we've 105 00:09:24,239 --> 00:09:30,356 written up to this time. So it's got you have an array of vertices 106 00:09:30,356 --> 00:09:36,310 that we've been to. It's got an edge two array which is the 107 00:09:36,585 --> 00:09:45,011 how do we get to each vertex so we can provide the client with the flow so that 108 00:09:45,011 --> 00:09:51,647 we can process paths in the graph you know, it's got the value of the flow. 109 00:09:51,647 --> 00:09:56,085 So, let's look at the code, it's kind of self-documenting. 110 00:09:56,300 --> 00:10:00,810 So what we'll do is we'll set the value of the flow to zero. 111 00:10:01,061 --> 00:10:07,851 So we're going to find out if it has a augmenting path and we'll look at that 112 00:10:08,102 --> 00:10:13,866 method in a minute. As long as it has an augmenting path then 113 00:10:14,109 --> 00:10:20,018 when we call, it has augmenting path, basically what that's going to do is 114 00:10:20,261 --> 00:10:26,898 that's going to do a graph search and mark the verticies that it visits and if it 115 00:10:26,898 --> 00:10:33,454 gets to this target, it's going to leave that path and now the edge to array in the 116 00:10:33,454 --> 00:10:40,313 standard way. the edge to of t contains the, the edge that, that contains the 117 00:10:40,313 --> 00:10:47,816 vertex that took us to t and so forth. And so we'll use that edge to, to go back 118 00:10:47,816 --> 00:10:52,544 through the path and to figure out the bottleneck capacity, 119 00:10:52,544 --> 00:10:58,898 Which is the minimum of the bottleneck capacity and the residual capacity in the 120 00:10:58,898 --> 00:11:05,977 high edge that we're processing. So that's the, the maximum amount of flow 121 00:11:05,977 --> 00:11:12,390 that we can push through the network does go through the path and find the minimum 122 00:11:12,390 --> 00:11:18,802 of either the unused capacity in some forward edge or the available flow in some 123 00:11:18,802 --> 00:11:23,077 backward edge. So once we have the bottleneck capacity, 124 00:11:23,127 --> 00:11:29,648 then we just go back through the path again and addResidualFlow to every edge in 125 00:11:29,648 --> 00:11:33,094 that path. So that's augment the flow. 126 00:11:33,094 --> 00:11:38,846 And then, once we've augment the flow, then we update the value. 127 00:11:39,112 --> 00:11:46,349 Notice that, when this terminates it terminated because we couldn't find an 128 00:11:46,349 --> 00:11:52,446 augmenting path, and we couldn't find an augmenting path meant that, essentially, 129 00:11:52,446 --> 00:11:59,436 we did a graph search that got stuck with finding all full-forward edges or empty 130 00:11:59,436 --> 00:12:04,567 backward edges before getting to the target and that's precisely the 131 00:12:04,567 --> 00:12:08,880 computation that we needed to do to compute the cut. 132 00:12:09,128 --> 00:12:13,598 So to tell whether a vertex is reachable from s. 133 00:12:13,847 --> 00:12:20,801 We just checkmarked v so we can tell the client which vertices are in the cut. 134 00:12:20,801 --> 00:12:28,460 And then we can find the, the edges that leave that vertex with the edges that 135 00:12:28,460 --> 00:12:34,185 comprise the cut. so now, all we have to do to finish is to look that it has 136 00:12:34,185 --> 00:12:39,477 augmenting path, which is the graph search in the residual network. 137 00:12:39,477 --> 00:12:45,536 And for this example we'll use breadth-first search although the other 138 00:12:45,536 --> 00:12:52,132 search algorithms that we've studied can be adapted in the same way depth-first 139 00:12:52,132 --> 00:12:58,344 search or using a priority queue as in Prim's algorithm or Dijkstra's algorithm. 140 00:12:58,574 --> 00:04:54,486 So we have our standard edge to in marked arrays and so we already have a queue 141 00:13:05,485 --> 00:13:12,420 which is going to contain the vertices that we've encountered but not yet 142 00:13:12,420 --> 00:13:16,918 visited. We'll put the source on there while the 143 00:13:16,918 --> 00:13:20,855 queue is not empty, we'll take a vertex off. 144 00:13:21,229 --> 00:13:27,696 And so, we'll go through everybody associated that's connected to that 145 00:13:27,696 --> 00:13:33,975 vertex, that's a flow edge. And then, you check the residual capacity. 146 00:13:34,350 --> 00:13:39,515 And if, if it's bigger than zero that means h, you have a way to get to w, and 147 00:13:39,515 --> 00:13:43,659 if it's not marked, You haven't been there yet then you go 148 00:13:43,659 --> 00:13:48,482 ahead and go there and mark it. It's essentially a breadth-first search. 149 00:13:49,490 --> 00:13:52,965 So that's the code for has augmenting path. 150 00:13:52,965 --> 00:13:59,653 And that essentially completes the implementation of breadth-first search. 151 00:13:59,913 --> 00:14:04,778 And mark t tells the, tells the returns true or false. 152 00:14:05,038 --> 00:14:11,900 If you can get from t to s after that search is gone, then t will be marked, and 153 00:14:11,900 --> 00:14:16,330 you can return true. This method can return true. 154 00:14:16,591 --> 00:14:20,500 That's a Java implementation of the max flow.