 In this video we are going to look into another example of how we can use the recursion and the looping strategy to implement iteration. In particular we are going to look at the so called Fibonacci numbers. There is a big difference in this video in comparison to the previous videos. So in this video we will see that one of the two approaches is clearly better than the other and in previous videos this was not the case. In previous videos both approaches basically were very readable code and also in terms of the speed of the running program both solutions were always efficient but in this video this will change now. So let's start a new file and let's call it Fibonacci and let's talk a bit about the so called Fibonacci numbers. So what are Fibonacci numbers? So basically it goes like this. Given the first two Fibonacci numbers which are defined to be 0 and 1 the next number is always or is simply the sum of the previous two. So let's do a sequence of Fibonacci numbers starting with the first numbers being 0 and 1 and 0 and 1 if we add them together we get the third Fibonacci number which will be 1 again 1 plus 1 then gives me 2 and 1 plus 2 will give me 3. So we see that it seems like the numbers are rather small but they have a very strong growth actually built in. So let's continue. So 2 plus 3 will be 5 and 3 plus 5 will be 8 and 5 plus 8 will become 13 and so on. So these are this is a sequence of Fibonacci numbers. Of course the Fibonacci numbers they go technically speaking into eternity so the sequence doesn't stop and the numbers as we see they will become bigger and bigger at an increasing rate. So the growth behind that sequence is very high. So let's think about how we can use this example of numbers to come up with two strategies to solve the problem to write a function that calculates the Fibonacci number. So in particular the task is going to be given an index let's call it I calculate the corresponding Fibonacci number. So let's briefly review what indices are. So indices in Python are just the numbers 0, 1, 2 and so on all the natural numbers but we started 0 because Python is a zero based language. So in other words the index for the first number the number 0 would also be the index 0. The second index for the number 1 would also be the number 1 but then the index for the third Fibonacci number which is also 1 would then be 2 of course. And so that is a task that we want to solve. Given an index let's calculate the corresponding Fibonacci number. So we can view the problem in two ways. First if we look at the example numbers here we can view the problem from left to right but also we can view it from right to left. And this is kind of similar to the discussion of how we could view the factorial of a number also in two different ways. So let's do the following I will now go ahead and draw a diagram because that is the easiest way to explain how Fibonacci numbers work. So let's go ahead and first write a couple of index numbers on the paper here. So the first index is of course 0 then it's going to be 1, 2, 3, 4, 5, 6 and then let's put a couple of dots here. So the task is to define a function so let's abbreviate this with simply Fib as Fibonacci and the function takes one argument and let's call it I the index and the task is to find the corresponding Fibonacci number. So let's pretend that we don't know what the Fibonacci numbers really are. We know the Fibonacci numbers of course for small numbers but of course for big numbers if you want to calculate let's say the 1000th Fibonacci number then of course we don't know what the number is. So now by definition the first and the second Fibonacci numbers are given as 0 and 1 by definition. We could also change the definition but this is just what mathematicians came up with. And now let's use an example and the example is going to be let's calculate the Fibonacci number for the index 5. Let's do that by hand. So we want this number we want to find this number and now we are going to use a right to left approach first. So this is going to be the recursive approach and so now how does this work? Well we know that whatever Fibonacci number will be here will be the sum of the previous two. So in other words we can say Fibonacci of 5 of index 5 can be broken down into a sum of basically two numbers and let's maybe make this a bit wider here. So the first one is going to be whatever Fibonacci number we get with the index 4 plus whatever Fibonacci number we get back with the index 3. So whenever we have a node here we basically add whatever numbers come back up here. Simple summation. So now if this here is the Fibonacci number with index 5 that we want to calculate and we have broken down the problem into finding the Fibonacci number with indexes 3 and 4, how do we continue from here? Well let's first go with the left hand side here Fibonacci of 4 which is this number here. So how can we calculate this? Well Fibonacci of 4 can be broken down further into the sum of Fibonacci number with the index 3 plus the Fibonacci number with the index 2 of course. So now we are basically here in those two spots here. So now if you want to calculate the sum what we need to find first is we need to determine whatever Fib of 3 and Fib of 2 is. Otherwise we cannot sum it up. So until we get some numbers from bottom up here until then we cannot do the sum summation yet. So we have to still wait in a way. So this is similar to how functions in a recursion have to wait in memory until another function call is done. This is basically what we are doing here by hand. So let's continue with finding the Fibonacci number with index 3. So how can this problem be broken down? Well it is the sum of Fibonacci of 2 plus Fibonacci of 1. So let's break this down. So this is Fibonacci of 2 plus Fibonacci of 1. And let's continue our approach to go always left first. So in order to find Fibonacci with index 2 which is this number here that we don't know we can break down the problem into the sum of those two Fibonacci numbers. So this is going to be the sum of Fibonacci of 1 plus Fibonacci with index 0. And now for the first time in this diagram what we can do is we can say well Fibonacci with index 1 and index 0 by definition is known. So we can say here we get back 1 and here we get back 0. And now this note here can do the summation. So 1 plus 0 gives me 1. Now let's go ahead the note where we are trying to calculate the sum of Fibonacci of 2 plus Fibonacci of 1. For Fibonacci of 2 we just calculated the result and for Fibonacci of 1 we basically know the result. Therefore we can go ahead and simply add 1 plus 1 here which gives me 2. So what do we know from this? Well Fibonacci of 2 we can basically plug it in here. So to say we could say Fibonacci of 2 would be 1 and Fibonacci of 3 would be 1. And Fibonacci of 3 would be 2. But again we are not going from left to right here. From left to right this is kind of obvious but we are going from right to left here. So now let's continue here with Fibonacci of 4. So finding this number here and to do so we have to add Fibonacci of 3 plus Fibonacci of 2. Now we have a problem. The left hand side we know the answer but the right hand side we really don't. So in other words whenever I write in some number up here in orange then this number is not really standing there. It's just something that we calculated on the fly from the bottom up here. So what we need to do here to calculate Fibonacci of 2 is we still need to break down the problem into Fibonacci of 1 plus Fibonacci of 0. And this of course is the same as 1 and 2. These are the base cases so we have 1 and 0 coming back. Fibonacci of 2 is the sum of that so it is 1 plus 0 which is 1. And now Fibonacci of 4 is 2 plus 1 which gives me 3. So we could write the 3 here but remember that all the numbers are right here in orange. They basically don't exist there so this is just temporary. And so what we see is if you want to calculate Fibonacci of 5 and if you break down the problem into finding Fibonacci of 4 plus Fibonacci of 3 many, many calculations need to be done until we get to the bottom of the tree. This is a tree structure and at the bottom of the tree what we see is we find the so-called base cases, the two only numbers that are given by definition. And now in order to finish calculating Fibonacci of 5 we still have to calculate the right-hand side here and the right-hand side goes like this. In order to find Fibonacci of 3 with index 3 this will be Fibonacci with index 2 plus Fibonacci with index 1 and Fibonacci with index 2 can be broken down into two further steps. Let's put them right here. This would be Fibonacci of 1 plus Fibonacci with index 0. And those nodes down here they will give me back 1 and 0. I sum them up here which gives me 1 and here because by definition I get back 1 I get 1 plus 1 which gives me 2 and so now next step would be to finalize the calculation 3 plus 2 gives me 5 of course. So let's write it here. So this would be the number of 5 and we can also see it here going from left to right 2 plus 3 would of course be 5. But again we want to do the recursive approach first. So what can we already see here in the recursive approach? Well we see that a lot of redundant work has to be done. So sometimes when we go down and let's say we go to this Fibonacci of 2 here well Fibonacci of 2 here needed to be calculated from scratch basically because we don't know what these Fibonacci numbers are. They all need to be calculated. But here on the left hand side we already calculated Fibonacci of 2. So we are doing redundant work here. So this Fibonacci of 2 here on the left hand side this is the first time we calculate Fibonacci of 2 and here we could look up the result but we can't really because we need to learn a bit more about programming before we can do that. And on the right hand side on the tree here we also see Fibonacci of 2 here. The same with Fibonacci of 3 which is here and here. Fibonacci of 2 which is here, here and here. So we have lots of nodes where we calculate redundantly the same Fibonacci number given the same index. Okay, so for now let's go back into JupyterLab and now let's write a function that implements the approach that I just throw you on the piece of paper. So let's define a function and let's call it simply Fibonacci and this function takes one parameter as its input which is going to be I an index number and let's go ahead and write a nice doc string so calculate the IS Fibonacci number then arcs is of course I which is an integer and this is the index of the Fibonacci number to calculate and this function also returns something namely it returns let's write it down as IS Fibonacci and this is also going to be an integer and now let's implement that using a recursion so in a recursion the base cases is basically what you see also in the example which is given okay so let's go ahead and say if I the index of the Fibonacci number to calculate is 0 then we know by definition of the problem that the answer is going to be 0 so we simply go ahead and say return 0 now we're going to say elif I is equal to 1 in that case we go ahead and we say return 1 so now note or remember how elif work so the condition after elif is only executed and checked if the condition in the if clause is false so in other words if the first condition is true we hit the first clause the first return 0 at the return statement if however the first condition is not true then we check the second condition and if the second condition is true then we are going to return 1 okay and these are both the base cases so in this example we actually see that there are problems in the world who have two base cases so base case let's call it number 1 write it like this and here we have base case number 2 and now we are not yet done with the recursion so for now we still have to go ahead and write else and now let's go ahead and now we have to do the recursive step so let's say i is 5 just like in the drawing so what do we need to do well we have to do the following we have to call the function of Fibonacci has to call itself 2 more times now so first it has to call it with i and subtract 1 from it and then to this we add whatever Fibonacci Fibonacci gets us the answer for i-2 okay so i-1 is the number that precedes whatever number we are looking for immediately so it's basically the next number, the previous number and Fibonacci of i-2 is the number that precedes the previous number so it's the number that is two numbers before the number we are looking for and that is the result therefore we are going to return that and of course as we saw in one of the previous videos what we can do is because we know by now that whenever a function hits a return statement the function is done what we could do is we could remove the else clause again and unindent this return statement just like this so this is the recursive case and my claim is that this function is correct so let's check that first by calling it with an argument of 0 so I want the first Fibonacci number with index 0 I get back 0 by definition that works and let's go ahead and get the second Fibonacci number with index 1 I get back 1 and now let's try to get back the 13 here the 13 has which index well 0, 1, 2, 3 so 0, 1, 2, 3, 4, 5, 6, 7 so index 7 should give me back 13 so let's check index 7 gives me back 13 just as expected so this function works it solves the problem from right to left so to say in a backwards fashion kind of and now comes something that is not so trivial but something that we can already guess from the picture I just drew so let's go ahead and look at some topic which is called efficiency of algorithms in particular here we are going to look into so-called exponential growth so what do I mean by that so as an example let's go ahead and calculate the 25th Fibonacci number so let's go ahead and say Fibonacci with index 24 let's see how fast this function is it's very fast rather fast I would say okay so let's go ahead and calculate the 37th Fibonacci number with index 36 so let's go ahead and use an index of 36 and now see what do you see here you see that this cell here calculates quite some time so if I maybe execute all the Fibonacci calls here one more time we see the first couple of ones are very fast the one with index 24 is also rather fast but with index 36 we see that Python needs some time we see that with the star here the star basically indicates that the Troubledalab is still calculating and it needs some time to find the answer okay and let's see there is in Python in Troubledalab to be precise there is something built in which is called time it magic and no space here so what this time it does is it calculates or it measures how long this cell is going to run so if I copy paste maybe this up here then instead of the result I simply get back how much time the function needs so if I call a function with 24 as the argument it takes 16 milliseconds and if I call it with 36 it takes 4.3 seconds and let's do one step further let's call a function with an argument of 37 so I just add 1 to the input and let's see how long the function runs so we have to wait a bit and we have to wait longer than before and let's wait more and now it says 7 so roughly speaking it should be twice the time the cell from the cell before so in other words adding 1 to i so increasing the index i by 1 should roughly double the amount of time the length in which it takes for the function to finish ok so why is it not exactly twice as much well because on my computer and also on your computer other processes are running in the background so the Python process here does not always 100% of the processor so therefore there is some rounding errors of course but it's roughly twice the time ok and let's do one more example to finish showing the effect here if I take 38 and then I should roughly have roughly 15, 16 seconds so now we have to wait a bit more and we see that as long as this cell is being executed we cannot do anything here really right we have to wait until the program finishes less than expected but still it's roughly twice the time so why is that so the reason for that is because as we saw in the picture I show that whenever I call Fibonacci with some argument i let's say 5 here I don't just call Fibonacci so Fibonacci does not just call itself for as many times as the number suggests so Fibonacci 5 does not lead to the Fibonacci number being called 5 times but if I call Fibonacci with an index of 5 I have 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 and I think I forgot this so 15 more calls ok so in other words if I want to calculate Fibonacci 5 the function has to call itself 15 more times and the reason why is because it does redundant work so as we noted before if you go from right to left then we are doing redundant calculations so calculations that we have actually done before for which we actually know the answer ok so that is true in this case and we could also see that in the code because we can think of it like this whenever we call the Fibonacci function the Fibonacci function sometimes in the recursive case calls itself 2 more times ok so in other words for each call we make the function calls itself 2 more times unless we are in the base case right so let's say the Fibonacci function is called once from us it calls itself 2 more times and the 2 more times the function calls itself will lead to 4 more calls and the 4 more calls will lead to 8 more calls so in other words for every round of calls the number of function calls doubles ok and that is unfortunately an example of let's call it here of exponential growth here so when we talk about exponential growth what we really talk about is what is the time unit it takes for the number of function calls to double so for the number of the computational steps to double and here it is for every let's say whenever we increase index by 1 the number of function calls needed to calculate the solution for this problem just doubles ok and if you want I suggest to if you further want to dig into understanding recursive calls using with exponential growth I suggest you simply copy paste the function and you copy paste it into Python Twitter and you see also in Python Twitter how the function calls itself over and over again even with the same arguments ok it makes redundant calls you can easily see that in Python Twitter as well so that is bad we see that this is bad because the function just takes forever so the question now is is there a better approach and the answer is of course yes there is and the better approach is let's right here alternative looping approach ok so now we are going to solve the same problem the same Fibonacci problem but we are not going to use a recursion but we are going to use a looping approach in particular a for loop so why can we use a for loop here so just remember that you can always use a for loop for any kind of iteration problem if the number of iterations the number of times where you need to make some repetition is predictable so in other words if I say let's see I want to calculate the number 13 which is the Fibonacci number with index 7 as we saw then we see that the first two numbers are given and then I need one iteration to calculate the one I need the second iteration to calculate two a third iteration a fourth iteration a fifth iteration and a sixth iteration ok so we remember to calculate Fibonacci the Fibonacci number for index 7 I need five iterations so five loops so in other words it is just the number of the index minus two this is the number of loops we need of iterations through the for loop that we need and therefore we can use the for loop it's predictable so let's also do that here in a diagram so that in this diagram you also learn how we can solve the problem so let's start with the first two numbers that are given as zero and one so they are just given ok so now what we do is what we are going to do is we are going to give two names two variables that reference these numbers so at first I will introduce a name a and a name b and a and b are going to refer to zero and one ok so let's go ahead how can I obtain the next Fibonacci number well we know that the next Fibonacci number is zero plus one so in other words it is a plus b ok so let's go ahead and add a plus b and this gives me of course one and now what I need to do is I need to go ahead and I now need to move so to say my variables so what I now need to do in order to get to the next step so the problem is um find Fibonacci for i equals seven so what we now do is we will remove our variables and we will basically move the variables one to the right and now we will add a plus b again and this is one plus one which will give us two and in the next step we are going to move a and b one further to the right and now they point to one and two and now we add a plus b and this will give me three and then one more so I'm not going to draw that everything here but now if you go ahead we need a further iteration which gives me five and then we need one more iteration which gives me three plus five which is eight and then actually we need one more to get to iteration seven to seven which is five plus eight which gives me back thirteen okay so this would be maybe I write it here this would be index seven and this here would be index zero of course so now let's see how we can use that idea that I just developed that we have moving variable names how we can use that idea in Python code and write a looping version for that so let's do that so let's go ahead and inside the function let's go ahead and set a to zero and let's set b to one okay and now we have to write a for loop so we are going to write for and for now we don't know what we are looping over so let's simply call it x and let's go ahead and say for x in range and in the range object we now have to come up with some number so that the number of iterations that the for loop does is correct so again let me go to the example above let's say if I want to get to the thirteen how many iterations do I need well the zero and one are given I need one two three four five six iterations okay so let's go further down and see how we can do that here so for now let's simply go ahead and put the I in there we will have to change it so the I is not yet correct but for now so that we get a working function let's simply write it as I and now let's see what we have to do in every iteration well in every iteration we now have to go ahead and simply add a plus b this gives us a sum the sum of the next number the next number so how would we call that well we could call it next number this is one way however because this variable as we will see is a temporary variable we could also simply call it temp for a bit shorter but you see from a conceptual point of view is it just the next number so now after we have calculated the next number what we need to do is we need to change A and B as we just saw in the diagram I drew so how do we do that well we know that our new A so the A was always the number on the left hand side so the new A so let's look at this here so the new A is my old B right this is what happens in the iteration so in other words my new A is simply my old B write it just like that in code and what is my new B well my new B is my next number ok so my new B is nothing but temp ok and then that is the for loop and now this loop is going to run a couple of times and after the for loop is done we need to return some result so let's simply go ahead and say let's return B ok we could also return temp ok so maybe we can make this a bit clearer maybe let's rephrase it into next number and then we are simply going ahead and simply return the next number however note we could also simply return B here right because B and next number is basically the same after the last step in the for loop so let's go ahead define the function and let's call the function fibonacci loop for an index 7 ok and I get back 21 and that is of course the wrong result so what happened here well in order to find out what goes wrong my suggestion is to use a print function inside the fibonacci loop function to get some intermediate output so let's do that print out whatever A and B is and we will end that with an empty on an empty line and inside the for loop after we calculated the next number what we are going to do is we are simply going ahead and we will print out whatever the next number the next current number is and we will also put that on one line and now if I execute the function again I see exactly what the problem is I am using one too many so how do I fix that well I fix that by simply saying instead of range of i I simply say range of i-1 so in other words we have the loop one less time now if I go ahead and say fibonacci loop with 7 argument e i is said to 7 will give me back 13 which is the same 13 I got back up here that is how you come up with a solution using a looping approach and then of course once you are done and you know your program is correct then it makes sense to of course get rid of the print function calls here again and now we see that this fibonacci function also gives us the same result so now let's do the experiment so up here we saw that the recursive version takes forever to calculate these numbers so let's go ahead and also calculate fibonacci the same numbers that were slow above so fibonacci with index 24 very fast but it was also fast above let's calculate fibonacci of 36 which was already slow up here it took 4 seconds to basically calculate the result so if you do that here it's basically there in an instant also if I go ahead and calculate the 999th fibonacci number so this is really the fibonacci number because we start to count at zero so this would be it very fast if I go back up to this cell here and if I call the normal fibonacci function the recursive version with the index 999 this now calculates forever literally okay so without doing any calculation of how long this algorithm or this code here this code cell may run I can already guarantee you that this will take several years to finish so the only way to finish the cell is to really stop it here with the keyboard interrupt okay so what we see here is that using the looping approach we can actually solve a problem very easily in a very good time so it's very fast algorithm but using the recursive approach up here we cannot really solve the problem for big input okay so that is a big problem however why do I like the fibonacci function in the recursive formulation what I like here is that I would claim that this function is a lot more readable okay if I don't tell you what fibonacci numbers are and I just show you this code here this function well you could guess what it is you can say well whatever fibonacci of i is it is the sum of its two predecessors of i-1 and then we have a base case here two base cases okay so this code I would guess is easier to read and easier to come up with if you know what you're doing of course if you see the general relationship which is basically the two predecessors added is the next number the approach down here using the loop we just saw as I did it that it's not so easy to come up with how often do I need to loop but you really have to think about how often do you need to loop you really also need to understand how the A and B works here so this is how my guess is that this solution is maybe a bit trickier to find however this solution has a big advantage it is faster it is way faster it is exponentially faster than the upper solution so for fibonacci this is the only approach that we can actually use in practice however that being said in a future chapter when we talk about the so called dictionary data type we will review this version the recursive version and we will make this version fast so maybe just to give you a quick idea of how we can do that so in our actual graph here when I calculate fibonacci of 5 and I calculate fibonacci of 4 and this break this down and I go down this path here once I get for example to this fibonacci of 2 here I already know that I calculate the result so if only I could store the result of this node here somewhere away in some book where I can basically simply write in all the temporary examples of intermediate results that we already had and then I could simply go ahead and look up the results from here ok and this is what we will learn in a future chapter of how to do it but for now we just have to live with the fact that the recursive version is simply not efficient so let's quickly go ahead and finish up the looping version make it look nice so one thing that I just want to mention if you write a for loop and the variable over which we loop so x in this example we don't need it and we see that we don't need it because we don't use x here so know where we use x here what you do in python is this is a convention we simply replace it with a variable called underscore so underscore has many different meanings in the python world but one meaning is that we don't use the variable we don't need it but for syntactical reasons we need it so if I leave away the variable in a whole then I will get a syntax arrow so I must specify a variable here for syntactical reasons and since I don't need the variable I simply go ahead and specify it as underscore that's just the convention and then also something that we can do we can get rid of the next number variable here so let's replace return next number with simply return b because we know that b is equal to the next number in the last step and now what we need to do is we need to update a and b simultaneously so what we could do is we could do the following we could write it on a line on its own so we could do the following copy paste this down and I get rid of the first and the last line and this line here, this one line will now simultaneously go ahead it will first evaluate the right hand side so the first part before the comma will just be b and the second part will just be a plus b and then the two results so b the value of b and the value of a plus b will be stored into a and b so this is basically how we can simultaneously update variables and let's check if everything works it does we have a nice version of Fibonacci a looping version which basically solves the problem in an efficient way so this is it for this video please review recursion if you still have troubles using it and also take some time to understand why this function is not so good so draw a diagram on your own run this recursive version in python tutor do whatever it takes to understand what goes on and why this is not a good solution here and then I will see you in the next video