I'm going to use approximate dynamic programming to help us model a very complex operational problem in transportation. Now, this is going to be the problem that started my career. This is some problem in truckload trucking but for those of you who've grown up with Uber and Lyft, think of this as the Uber and Lyft trucking where a load of freight is moved by a truck from one city to the next once you've arrived, you unload just like the way you do with Uber and Lyft. This is a picture of Snyder National, this is the first company that approached me and gave me this problem. The challenge is to take drivers on the left-hand side, assign them to loads on the right-hand side, and then you have to think about what's going to happen to the driver in the future. Now, in this industry, instead of taking 10-20 minutes to finish the trip, this can be one to three days which means once I finish the trip it's several days in the future, and I have to think about whether I want to move that load, and then what's going to be the value of the driver in the future. Let's illustrate this using a single truck. I'm going to call this my nomadic trucker. Maybe this is a driver starting off for the first time and he happens to be in Texas, and he goes to his website and can see that there's four loads that he can move each at different rates. He has to think about the destinations to figure out which load is best. But he's new and he doesn't know anything, so he's going to put all those downstream values at zero, he's going to look at the immediate amount of money he's going to make, and it looks like by going to New York it's $450 so he says, "Fine, I'll take a look into New York." Now, before we move off to New York, we're going to make a note that we'd need $450 by taking a load out of Texas, so we're going to update the value of being in Texas to 450, then we're going to move to New York and repeat the process. Now, I could take this load going back to Texas,125 plus 450 is 575, but I got another load go into California that's going to pay me $600, so I'm going to take that. Let's first update the value of being in New York, $600. Now I'm going to California, and we repeat the whole process. Now, here things get a little bit interesting because there's a load in Minnesota for $400, but I've never been to Minnesota. So I still got this downstream value of zero, but I could go to Texas. I've got a $350 load, but I've already been to Texas and I made 450, so I add the two together and I get $800. I'll take the 800. We'll come back to this issue in a few minutes. So we go to Texas, I repeat this whole process. Now, I've got a load in Colorado. Now, once again, I've never been to Colorado but $800 load, I'm going to take that $800 load. Now, the last time I was in Texas, I only got $450. So what I'm going to have to do is going to say well the old value being in Texas is 450, now I've got an $800 load. What we going t do is now blend them. This is known in reinforcement learning as temporal difference learning. I'm going to say take a one minus Alpha. Lets set Alpha to be 0.1, so I'm going to take 0.9 times my old estimate of 450 plus 0.1 times this updated value of 800 and get a blended estimate of 485. So this will be my updated estimate of the value being in Texas. So this is something that the reinforcement learning community could do a lot with in different strategies, they could say well they have a better idea, but this illustrates the basic steps if we only have one truck. So what happens if we have a fleet? So let's imagine that we have a five-by-five grid. So we'll call that 25 states of our truck, and so if I have one truck, he can be in any one of 25 states. If I have two trucks, and now we have all the permutations and combinations of what two trucks could be. If i have six trucks, now I'm starting to get a much larger number combinations because it's not how many places the truck could be, it's the state of the system. Now, there's a formula for telling me how many states of my system is the number of trucks plus the number of locations minus one choose the number of locations minus one. If I have one truck and one location or let's call it an attribute because eventually we're going to call it the attribute of the truck, if I have a 100 locations or attributes, I have a 100 states, if I have 1,000, I have 1000 states, but if I have five trucks, we can now quickly cross. If I only have 10 locations or attributes, now I'm up to 2000 states, but if I have a 100 attributes, I'm up to 91 million and 8 trillion if I have a 1000 locations. But what if I have 50 trucks? That's just got really bad. Guess what? My fleets may have 500 trucks, 5,000 as many as 10 or 20,000 trucks and these fleets are really quite large, and the number of attributes, we're going to see momentarily that the location of a truck that's not all there is to describing a truck, there may be a number of other characteristics that we call attributes and that can be as large as 10 to the 20th. We need a different set of tools to handle this. So now I'm going to illustrate fundamental methods for approximate dynamic programming reinforcement learning, but for the setting of having large fleets, large numbers of resources, not just the one truck problem. So let's assume that I have a set of drivers. There may be many of them, that's all I can draw on this picture, and a set of loads, I'm going to assign drivers to loads. Now, this is going to evolve over time and as I step forward in time, drivers may enter or leave the system, but we'll have customers calling in with more loads. So these will be evolving dynamically over time, and I have to make a decision back at time t of which drivers to use and which loads to use, thinking about what might happen in the future. Now, let's go back to one driver and let's say I have two loads and I have a contribution, how much money I'll make, and then I have a downstream value for each of these loads, it depends on the attributes of my driver. For the moment, let's say the attributes or what time is it, what is the location of the driver, his home domus are, what's his home? Because eventually, I have to get him back home, and how many hours he's been driving? Those are called hours of service rules because the government regulates how many hours you can drive before you go to sleep. Now, we can take those downstream values and just add it to the one-step contributions to get a modified contribution. So this starts to look like a fairly simple problem with one truck. Now, if I have a whole fleet of drivers and loads, it turns out this is a linear programming problem, so it may look hard, but there's packages for this. If you're looking at this and saying, "I've never had a course in linear programming," relax. Several decades ago I'd said, "You need to go take a course in linear programming." But today, these packages are so easy to use, packages like Gurobi and CPLEX, and you can have Python modules to bring into your Python code and there's user's manuals where you can learn to use this very quickly with no prior training linear programming. These are powerful tools that can handle fleets with hundreds and thousands of drivers and load. So all of a sudden, we're scaling into these vectored valued action spaces, something that we probably haven't seen in the reinforcement literature. Now, let's say we solve the problem and three of the drivers get assigned to three loads, fourth drivers told to do nothing, there's a downstream value. Now, look at what I'm going to do. This is the key trick here. I'm going to subtract one of those drivers, I'm going to do this for each driver, but we'll take the first driver and pull him out of the system. So I'm going to drop that drive a_1 re-optimize, I get a new solution. The last three drivers were all assigned the loads. Now, what I'm going to do is I'm going to get the difference between these two solutions. The global objective function for all the drivers on loads and I'm going to call that v hat, and that v hat is the marginal value for that driver. Now, I actually have to do that for every driver. That doesn't sound too bad if you have a small number drivers, what if you have a 1,000? So it turns out these packages have a neat thing called a dual variable., they give you these v hats for free. Just by solving one linear programming, you get these v hats. So that's kind of cool for every single driver. So even if you have 1,000 drivers, I get 1000 v hats. Now, once you have these v hats, we're going to do that same smoothing that we did with our truck once he came back to Texas. We're going to have the attribute of the driver, we're going to have the old estimate, let's call that v bar of that set of attributes, we're going to smooth it with the v hat, that's the new marginal value and get an updated v bar. So it's just like what I was doing with that driver in Texas but instead of the value of the driver in Texas, it'll be the marginal value. So still very simple steps, I do a marginal value, I treat it just like a value. When I go to solve my modified problems and using a package popular ones are known as Gurobi and CPLEX. These are free to students and universities. If you go outside to a company, these are commercial systems we have to pay a fee. There's other tree software available. You have to be careful when you're solving these problems where if you need a variables to be say zero or one, these are called integer programs, need to be a little bit careful with that. But just say that there are packages that are fairly standard and at least free for University years. So let's say we've solved our linear program and again this will scale to very large fleets. Now I've got my solution, and then I can keep doing this over time, stepping forward in time. Now, I can outline the steps of this in these three steps where you start with a pre-decision state, that's the state before you make a decision, some people just call it the state variable. The green is our optimization problem, that's where your solving your linear or integer program. The variable x can be a vector and those v hats, those are the marginal values of every one of the drivers. The blue Step 3 is where you do in the smoothing, and then Step 4, this is where we're going to step forward in time simulating. So that W variable, that's going to be for one thing, all the new load to they get called in, but it can also be a driver that just called in and says, "Hey I'm ready to work," a driver may leave, or whether delays for travel times, but it's just a Monte Carlo simulation so it doesn't matter the dimensionalities of this. So now what we're going to do is we're going to solve the blue problem. So that's one call to our server. We're going to step forward in time simulating. But now I'm going to have to do this multiple times, and over these iterations, I'm learning these downstream value functions. If everything is working well, you may get a plot like this where the results roughly get better, but notice that sometimes there's hiccups and flat spots, this is well-known in the reinforcement learning community. Now, let's go back to a problem that I am quite touched on which is the fact that trucks don't drive themselves, it's truck drivers that drive the trucks. So if you want a very simple resource. Now by the way, note that we just solved a problem where we can handle thousands of trucks. So if we have our truck that's moving around the system, it has [inaudible] 50 states in our network, there is only 50 possible values for this truck. What if I put a truck driver in the truck? That just got complicated because we humans are very messy things. For example, here are 10 dimensions that I might use to describe a truck driver. Now, instead of just looking for location of the truck, I had to look at all the attributes of these truck drivers and in real systems, we might have 10 or as many as 15 attributes, you might have 10 to the 20th possible values of this attribute vector. It turns out we have methods that can handle this. So let's imagine that we have our truck with our attribute. Now, as the truck moves around these attributes change, by the way, this is almost like clean chess. A chessboard has a few more attributes as that 64 of them because there's 64 squares and now what we have to do is when we take our assignment problem of assigning drivers to loads, the downstream values, I'm summing over that attribute space, that's a very big attribute space. Now, it turns out I don't have to enumerate that, I just have to look at the drivers I actually have, I look at the loads I actually have and I simulate my way to the attributes that would actually happen. So big number but nowhere near to the 20th. Now, let's take a look at our driver. A driver going to Pennsylvania. I may not have a lot of data describing drivers go into Pennsylvania, so I don't have a very good estimate of the value of the driver in Pennsylvania but maybe I do have an estimate of a value of a driver in New England. So I can think about using these estimates at different levels of aggregation. Let's take a basic problem, I could take a very simple attribute space and just looking location but if I add equipment type, then I can add time to destination, repair status, hours of service, I go from 4,000 attributes to 50 million. What I'm going to actually do is work with all of these, all at the same time. So I'm going to hand this hierarchy of attributes spaces. Even though the number of detailed attributes can be very large, that's not going to bother me right now. Let's come up with and I'm just going to manually makeup because I'm an intelligent human who can understand which attributes are the most important. I'm going to make up four levels of aggregation. Now, the real truck driver will have 10 or 20 dimensions but I'm going to make up four levels of aggregation for the purpose of approximating value functions. Now, what I'm going to do here is every time we get a marginal value of a new driver at a very detailed level, I'm going to smooth that into these value functions at each of the four levels of aggregation. Now, I'm going to have four different estimates of the value of a driver. Now, what I'm going to do is do a weighted sum. Now, these weights will depend on the level of aggregation and on the attribute of the driver. Now, the weights have to sum to one, we're going to make the weights proportional to one over the variance of the estimate and the box square of the bias and the formulas for this are really quite simple, it's just a couple of simple equations, I'll give you the reference at the end of the talk but there's a book that I'm writing at jangle.princeton.edu that you can download. The equations are very simple, just search on hierarchical aggregation. Now, let me illustrate the power of this. If I were to do this entire problem working at a very aggregate level, what I do is getting a very fast convergence. Works very quickly but then it levels off at a not very good solution. If I work at the more disaggregate level, I get a great solution at the end but it's very slow, the convergence is very slow. If I use the weighted sum, I get both the very fast initial convergence to a very high solution and furthermore that this will work with the much larger more complex attributes faces. Here's an illustration where we're working with seven levels of aggregation and you can see in the very beginning the weights on the most aggregate levels are highest and the weights on the most dis-aggregate levels are very small and as the algorithm gets smarter it'll still evolve to putting more weight on the more dis-aggregate levels and the more detailed representations and less weight on the more aggregate ones and furthermore these waves are different for different parts of the country. So in the United States, we have a lot of people living a lot of density in the eastern part of the United States but as you get out into the western, not quite California, there's very people in the more less populated areas. We won't have as much data and we're going to stay putting higher weights on the more aggregate levels but as we get a lot of observations in the eastern part, we're going to put more weight on the dis-aggregate levels. So here we're going to also address that problem that we saw with the nomadic trucker of, should I visit Minnesota. Now, the reinforcement learning community will recognize the issue of should I have gone to Minnesota, I've got values zero but it's only because I've never visited for and whereas I end up going to Texas because I had been there before, this is the classic exploration exploitation problem. Now, the way we solved it before was to say we're going to exploit. I'm going to go to Texas because there appears to be better. Now, there's algorithms out there will say, yes, but I maybe should have tried Minnesota. But now we're going to fix that just by using our hot hierarchical aggregation because what I'm going to do is using hierarchical aggregation, I'm going to get an estimate of Minnesota without ever visiting it because at the most aggregate levels I may visit Texas and let's face it, visiting Texas is a better estimate of visiting Minnesota, then not visiting Minnesota at all and what I can do is work with the hierarchical aggregation. Now, in our exploration-exploitation trade-off, what we're really going to do is view this as more of a learning problem. So let's imagine that I'm just going to be very greedy and I'm just going to do with based on the dis-aggregate estimates I may never go to Minnesota. If I run a simulation like that after many hundreds of iterations, I ended up holding visiting seven cities. So this is like the people who always go to the same restaurants and try and do the same things after a while you've randomly been forced in a small set of cities and you keep going back to those just because you've been there before. Clearly not a good solution and maybe I've never visited the great state of Minnesota but just because I haven't been there but I've visited just enough that there's always some place I can go to that I visited before. But if we use the hierarchical aggregation, we're estimating the value of someplace is a weighted sum across the different levels of aggregation. If I run that same simulation, suddenly I'm willing to visit everywhere and I've used this generalization to fix my exploration versus exploitation problem without actually having to do very specific algorithms for that. Let me close by just summarizing a little case study we did for this company Schneider National. I have to tell you Schneider National Pioneered Analytics in the late 1970s before anybody else was talking about this, before my career started. My career started in early 80s and they came to me asking how to do uncertainty, is it's where all of my work and approximate dynamic programming came. Now back in those days, Schneider had several 100 trucks which says a lot for some of these algorithms. Now, they have close to 20,000 trucks, that everything that I've shown you will scale to 20,000 trucks. In fact, we've tested these with fleets of a 100,000 trucks. Here's the Schneider National dispatch center, I spent a good part of my career thinking that we could get rid of the center, so we did it to end up these people do a lot of good things. Here's the results of calibration of our ADP based fleet simulator. They would give us numbers for different types of drivers and seeing if you use two statistics you've got to be within this range and so the model after a lot of work we were able to get it right within the historical ranges and get a very carefully calibrated simulation. This is a case where we're running the ADP algorithm and we're actually watching the behave certain key statistics and when we use approximate dynamic programming, the statistics come into the acceptable range whereas if I don't use the value functions, I don't get a very good solution. So this is showing that we actually get a more realistic solution, not just a better solution but more realistic. Now, here what we're going to do is help Schneider with the issue of where to hire drivers from, we're going to use these value functions to estimate the marginal value of the driver all over the country. Now, here's a graph that we've done where we took one region and added more and more drivers to that one region and maybe not surprising that the more drivers you add, better results are but then it starts to tail off and you'll start ending up with too many drivers in that one region. But doing these simulations was very expensive, so for every one of those blue dots we had to do a multi-hour simulation but it turns out that I could get the margin slope just from the value functions without running any new simulation, so I can get that marginal value of new drivers at least initially from one run of the model. This is from 20 different types of simulations for putting drivers in 20 different regions, the purple bar is the estimate of the value from the value functions whereas the error bars is from running many simulations and getting statistical estimates and it turns out the two agree with each other's which was very encouraging. These results would come back and tell us where they want to hire drivers isn't what we call the Midwest of the United States and the least valuable drivers were all around in the coast which they found very reasonable. They turned around and said, "Okay, where do we find these drivers?" But this is a very powerful use of approximate dynamic programming and reinforcement learning scale to high dimensional problems.