 And hello everybody, welcome to SciPy Optimization, and we're gonna be taking a look today at the minimize method of the SciPy library. So this is a little bit more complicated, a bit more mathematical than some of the stuff I usually do, but I thought it'd be an interesting thing to do. It's something I just learned in my grad course, so I thought I'd pass this on to all of you. So first a quick shout out to my members, especially like to give a shout out to Pete Q. Uli Bogdan and Ezra who have made it to their second month of membership. Thank you so much for supporting the channel. If you're interested in joining, please click join below or subscribe if you're more into that. But thanks to everyone who views, comments, subscribes and joins. Moving on today, we're gonna be taking a look at minimization. So minimization in this case is where we have a function and we want to find the minimum value. And this is what we're gonna be learning how to do today. So this is an arbitrary function, I just came up with it. So it's x squared minus 12x plus 20. I chose this example because we only have one variable, x. And then I'll do another example later where we actually have two and show you kinda how that works. So yeah, let's get started. Now this is something I just learned myself, so it might be a little bit rough, but I think I got it down. So the first thing you gotta make sure you have sci-pi installed. So sci-pi is a library that does scientific Python. And it works very well with pandas, which is another library for mathematical stuff. So let me go ahead and try pip3 sci-pi and that was wrong. So it's pip3 install sci-pi. Now you may already have it on your computer. Now you can see I've already got it installed. It uses numpy, I'm not sure if I said numpy or pandas earlier, but it uses numpy. That was close. Anyway, so it uses that library as well. So let's go ahead and click and start doing some typing. So it's a library, it's a module we need to import it. And so as I mentioned earlier, we're gonna be using sci-pi.optimize. And in my course, they said to import it like this as SPO. And but you can import it however you like. If you don't wanna type the whole thing in. So I'm just gonna go ahead and run this. I'm using the genie IDE here. I just wanna see if it imports. Okay, so program exited with code zero, that's good. If you see an error that doesn't know what sci-pi is, check your spelling, check the install, make sure it's installed correctly. I can't really hop in with that because I just know it works on my computer. So what we need to do, we need to understand how this is going to work is we need to create a function. And the function is what we want to minimize, in this case, minimize. And so what we're trying to do is we're trying to find the X value that gives us the lowest Y value. So I kind of have it circled here. So I mean, looking at the chart, we know what the answer is going to be. But imagine if we didn't. And so this is the process that we would go through. So let's take a look here. So I'm gonna go ahead and define my function. And I'm gonna call this f of X and put my call in there. And what I need to do is I need to calculate Y. That's what we're looking for. We're looking for the lowest Y. And so Y equals, now we're just doing the same, oops. We're just doing the same thing in Python. So it was X squared. Sorry, my stupid trackpad keeps doing that. So it's X squared, was it minus? I think it was 12 times X plus 20. So this is the formula. Now you might wanna, it's gonna work fine, but you might want to group these with parentheses, but it's probably not necessary in this case because of the order of operations. And then we just return Y. That's it, it's a very, very simple function. So what we're trying to do is to minimize Y. And what that'll do is if we minimize Y, that will find us the lowest point on this function. So we got X squared minus 12X plus 20. So now we need to do a few things. We need to come up with a starting guess. Okay, you know, the computer has no idea where to begin. So we just give it a guess that we think might be a good one. So I'm gonna call this X start. And now I mean, looking at it, we know it's probably gonna be six, but let's just say, all right, we'll guess two. We'll say it's gonna be, it might be 2.0. All right, and we'll get the bounds and constraints a little bit later, but right now we're just gonna go ahead and jump into optimizing. And this is what's really the power of this sci-pi library. It just kinda does it for you if you know how to send it the values that it's looking for. So we are looking for a result. Now this result is not gonna be Y, it's not gonna be X, it's gonna be an object, I'll get to that in a minute. So we're using the sci-pi optimization library, which we just did here. And then we're gonna go, we wanna use minimize. Now watch what I do here. The first argument I'm gonna put in here is F. And F came from here. So this is the function that we're minimizing. I didn't have to call it F, I just chose that. That's kinda how math usually works. Then the next argument is our guess. So in this case it is X start. Now there's a couple of options we can put here. I'm gonna leave this like this and see what happens. I haven't actually tested this, but I think that's all we really need. Where's my equal sign? There we go. Now what's gonna happen is it's going to basically do its magic. That's really all we have to do. So what we need to do is find out if there is a result. So we'll do if, so we'll say print result. So if result.success. So this tells us if this operation is successful. What we wanna do is, this is actually pretty easy, we can just go ahead and print, success. Then we'll just go ahead and print. I'm gonna use an F string here because that's probably a good practice to get into. And I'll say, X equals, and that should be result.x. And Y equals result.fun. Now fun is not fun fun, it's fun as in function. So whatever the minimum value, it's the result of this function that we pass to it is what it's gonna find. Now if I go over here and say else, print, sorry, could not find a minimum. And again, the key thing here is we are trying to minimize the function. We're not trying to maximize. I'll get to that in the next part of the video. So let's go ahead and save it. I'm gonna run it and see what happens. Okay, X to the code zero, that's a good sign. And you can see here, success, where X equals six, Y equals negative 15.9999. That's just a rounding error. So obviously we can see that Y is negative 16, where X is six. Let's go take a look back at our chart. And you can see that basically that's the answer. Okay, so at X equals six, Y equals negative 16. So I'm pretty happy with that. It's done its job. It's pretty simple actually. Now I've left out some details. I've left out a few things that we could see. But this is the basic structure of using the minimize method. Now, the minimize method has a ton of different options that are fairly advanced. I really don't know a lot about them myself. But this is how you would find the minimum of a function. Now this assumes that the function has a minimum or has a minimum in a certain range. And I'm gonna get to that I think maybe in the next part of this. But this is the general gist of it. So let's take a look at this. We've imported it. We've defined our function. And it's returning the value Y. And this is what we want to minimize. And then we have to give it a starting guess. Then we just call the optimization function. Now here's something, here's like a little option I can show you. So I can say options equals, and it's a little dictionary. You'll see DISP means display and true. And if we use this option, it'll give us a little bit more information when we're calling the optimization routine. So I'm gonna go ahead and kind of scroll up here a little bit. And you can see current function value. So negative 16. So it iterated through three times. It evaluated the function eight times and did four different gradient evaluations. Now I'm not gonna bother explaining what all that means, but basically it was doing a lot of stuff in the background. So it called this function multiple times. And then it did its mathematical, whatever calculation to try to find the minimum. I'm not gonna go into how it works because I don't know all the details myself, but long story short, it works. Now there are a number of different optimization routines you can do. Check out the SciPy documents. It's pretty complicated to be honest. But yeah, check it out, it's pretty cool. So what I'm gonna do is I wanna do the same thing, but I wanna do it with two variables. So a more complicated problem. So, and this time what I wanna do is I would actually want to maximize something. So let's go ahead and take a look at what that might look like. So I found this thing, found this actually Libre text, I'm assuming it's some kind of open source text. And they've got this problem, example 4.71, which is maximizing the area of a garden. So we've got a garden and we have a wall. So there's one wall already there. And we have x and x and we have y. Now it's weird because x is usually left and right, but we'll let that slide. But the thing, the key here is that you have 100 feet of fencing. So the question is, what is the maximum area that you can fence off if you have 100 feet of fence? So that's what we're gonna be working on here. So I'm gonna go back to the code that we just did. And we're gonna need to add a few things because we have some extra constraints we didn't have. So my function, now this is where it gets a little bit complicated. I'm gonna change this to x, y. And now, keep in mind, our function is returning the area. Now the reason I chose x, y is because we have two values. We have an x value and we have a y value. So to get x out of x, y, I'm gonna do x equals x, y, zero. So it's like a list. So y equals x, y, one. You'll see how I'm doing, passing that in a second. And the area is gonna equal x times y. That's the formula for area. Then we return the area. Now, the starting guess here, we've got 100 feet of wire. So let's say x is gonna be 50. I have no idea. Let's say x is 50. Well actually, I can't do x is 50 because I've actually got two things. So I've got x and I've got y. So let's say these are our starting guesses. So I'm gonna change this to x, y start. Again, this is getting a little more complicated because we've got two values. Instead of maximizing or minimizing as we did previously, one value, we're actually gonna do two values. So to do that, we've gotta make a list. And that's why I call this x, y start. And I put, this is gonna be my x because that's gonna be x zero or x, y zero. This is gonna represent my y. Now to do this, now my function hasn't changed. But I'm gonna do x, y start. Now what's nice about this is because I've given it two values, it automatically is going to do what it needs to do. It's that smart. Now down here, I have to make a couple changes. Okay, so I'm gonna say x, y, the result, which is what we're looking for, equals result.x. Now I didn't mention this before, I meant to, but I forgot to. This x does not equal this x or this x or whatever. Okay, this x is whatever we are optimizing. While we're optimizing for the result, but it's whatever we're sending to the function. So in this case, this is x. So it's returning them as a list. So once I've got x, y, I can say x equals x, y zero. I can say y equals x, y one. And then I can just say x equals x, y equals y. Okay, so now I'm gonna run this. Now it's not correct. Okay, I'm running this just to kind of show just kind of some things that are going on. I'm gonna go ahead and run it and see if it's working a little bit. Okay, so that's interesting. So we've got success. So you say x equals negative six, blah, blah, blah. So basically this is zero. Look at this e negative 12, e negative 12. So basically it optimized it down to zero so that we could minimize the values here. So this is clearly not what we want. We don't want a fence of zero. So in this particular case, we've got a constraint. So that's what we wanna put into this particular thing. So I'm gonna go ahead and add constraints. In this case, just one. So my constraints, constraints with PsiPy are a dictionary. And it's pretty complicated to be perfectly honest. It's actually, sorry, this is gonna be a list or a tuple of dictionaries. So I'm just gonna put one in for now. So one dictionary. So the type, I'll explain this in a second, is eq. The function that controls the constraint. And I said this was a little bit complicated. Is gonna be lambda. Now again, I'm assuming if you're watching this, you know what all this stuff means. So now the constraint is that we've got 100 feet of fencing. So if I go back to this, well, I gotta go back to here. So we've got 100 feet of fencing. But notice we have x, x and y. So the constraint is 2x plus y equals 100. So no matter how much fencing we have, it's gonna be x plus x plus y. So it has to meet that requirement. So to put that into a way that PsiPy can understand it, I'm gonna do the following. So it's gonna be 2 times x, y, zero. Because remember x is zero, which we've done earlier. Plus x, y, one, which is y. Now watch what I do here. You'd think you'd put 100. That is wrong. I don't know why, but this is the way it's done. You put minus 100. So because this says eq, what we're looking for is that this evaluates to 100. Oh sorry, excuse me. This evaluates to zero. So if this is 100, subtract 100, we would have zero. This is the constraint for this particular problem. So I'm gonna go ahead and put here constraints equals cons. Now I could have just taken this and put it right in here. But this makes it a little bit easier. So let's go ahead and run that again and see what happens. Invalid syntax. Come on, function, ah, that should have been a, that should have been a colon. Because this is a key in value. All right, so let's go ahead and try that again. Okay, so you can see here it says, could not find a minimum. Now, there's a reason for this. We are looking for the maximum, which is kind of tricky. So in this particular case, we're using the minimize function, or method, to maximize the area. So in this case, we're maximizing. So the easy way to do that is just return the negative of the area. So as the area gets basically smaller, it maximizes it. It's basically just return the opposite, which is pretty cool. Let's go ahead and run this, and here we go. Okay, now, you can see how the current function value is returning negative. But this is the maximum area that we can get out of this given that particular constraint. So we've got 24.999, which is 25, and we've got 50.000. So 24x, remember, it's two times x, x plus x plus y. So 25 plus 25 plus 50 equals 100. And that gives us an area of 1,250. I think the answer is here somewhere. So you can see here, yeah. So the answer does agree with their result. So it's pretty cool. So you can use this fairly simple code to calculate the maximum or minimum, assuming that the maximum or minimum exists, depending on your constraints and everything that you're sending. Now there's one more thing. We didn't really need it in this particular problem, but we can also add bounds. So I'm gonna go ahead and show you how to do that. Bounds. So a bound is a minimum and maximum value for your inputs. Okay, now it's a little tricky here because we've actually got two. We've got x or x and we've got our y. So our bounds would equal a tuple of tuples. So let's, now we've got 100 feet of fence. So let's say we gotta have at least one foot of fence, otherwise it would make sense. And the maximum would otherwise be 100. And then one and 100. So in the case of x and y, so x can be anywhere from zero or from one to 100, y can be anywhere from one to 100. And then to add our bounds equals bnds. And again, I didn't have to, or actually this should be bnds, sorry. And I'll put a link down below to the SciPy documentation and where they talk about all these things. So the bounds is this tuple. So this correlates to this first value and this correlates to, or this correlates to the second value. Now in this particular problem, these numbers work. So I'm assuming that if you're getting into SciPy, minimization, maximization, that some of this stuff will already make sense to you. So we're gonna run it, just make sure it works. And I'm still getting the same results because I didn't want to go outside of the bounds. Now, let's say in a case where if I go back to this problem, now let's say y was limited to 30 feet. Let's say this was only 30 feet wide. We could make a garden here, we could make a garden here. What would be the best with that limit? So let's go ahead and limit y and say limit y can only be 30 feet wide, just to see what happens. So remember, y is the second value. So I'll go ahead and put a 30 there. So this can be from one to 100, this can be from one to 30, but whatever we choose, the total has to be 100. Let's go ahead and run that. And you can see here in this particular case, our area is gonna be 1,050 and our x is 35, whereas our y is 30. So two times 35 is 70 plus 30 gives us 100. So it meets all of the criteria. So that is that. It's pretty cool what you can do with this. Once you learn how it works, it took me a long time to figure that stuff out and I was racking my brain on the weekend because I had an assignment to do with this kind of stuff. So let me just go through this real quick one more time. So we're using scipy.optimized and we import it as spo. We created a function. In this case, we are sending a list. So that's why I called it x, y. And in this case, the first value is gonna represent our x. The second value is gonna represent our y. So the indices are zero and one. Calculate the area and I'm returning the negative area. And the only reason I'm returning negative area is because I want to maximize. Remember, this is minimize. So if you want to maximize, you got to return the negative. You need to give it some starting values. So I just, you know, so 100, so 50 plus 50 is 100. So I said x is 50, y is 50. I also, we can give it boundaries. So we can say this value has to be between one and 100. This value has to be between one and 100. Okay, so in case like you might want to avoid negative numbers, for example. So yeah, you can do stuff like that. And then this constraint is an equality constraint. And we give it a lambda function. And we're passing, note that we're passing the same thing. We're passing this value to this particular constraint. So again, it was two times x, which is x, y, zero, plus x, y, one, which is y, minus 100 equals zero. And this is because the type is eq. So there's also an i, n, eq inequality, where this has to be positive. But I haven't really played around that much, so sorry. And let me just make that capital. So remember, this is the function that you are calling. This is the guesses that you're using in this case. It's a list, because we have two values, x and y. The options for display, there's other options, I believe, but this is the only one that I've used. We add the constraints, we add the bounds. And it just does its magic. There's nothing else to it. It's very, very simple. And then if there is a success, if it finds the maximum in this case, but it thinks it's a minimum, and the result that comes out of it, again, this x, it's just called x, that's what you have to use. But in this case, it represents our x, y. And then we pull out our x and we print the values that we need it. And then otherwise, if it's not a success, sorry, it could not find a minimum. So that is a real quick intro, what was this, 25 minutes, on how to use basic minimization, and in this case, maximization, but actually minimization, in the SciPy Library. Hope this was interesting to people. Again, it's not my usual kind of content, but yeah, I'm trying to branch out and try new things. And as I'm learning stuff, I want to introduce it to all of you. So again, thanks so much to the members and yeah, everybody else, join, subscribe, like, share, et cetera, et cetera. And as I'd say, keep on coding, take care.