 So, look at these answers. A says multiplication does not take very large time. It is the division operation and the addition operation which is time consuming. This is pure humbug, pure nonsense. It is traditionally known that the time required to do computations is roughly the smallest for addition and subtraction and largest for or much larger for division and multiplication. So, multiplication and division time does take long time. So, this is clearly not the answer. B says since i and j are varying computing i square j square each takes much longer than n square. It is very sad indeed that my colleague teachers many of them think that B is the right answer. Please understand that varying variation of i and j has nothing to do with the operation of computation of i square and j square. Let us go back to the formula and just check this. Please note that i and j are varying only once in the iteration. We are talking about the computation time consumed while executing this comparison within which we are doing this complex computing. When the computer comes to this particular point for executing or evaluating this expression, at that point the value of i, value of j and value of n 2 or earlier the value of n all are fixed. i and j are not varying when I am doing the computation. In fact, when I am doing the computation I cannot compute the multiplication sum or anything of two numbers which are actually changing while I do the computation. So, this is incorrect. It is actually a confusing statement. When I say varying some of us believe that there is something drastically wrong. That is all humbug. What is happening is that it is just a multiplication. Whether i has varied earlier and n has not varied earlier has no significance. Consequently, the answer B is also not correct. In short, whether i and j were varying or whether they were not varying, the time required to multiply i by i, the time required to multiply j by j and the time required to multiply n by n will exactly be same. There will be no difference whatsoever. I will first look at answer D. I do not know and also I cannot guess. As a novice, you will often find the first year students giving this answer. The correct answer is however C. Our program somehow figures that n is not changing. So, it calculates n square only once and uses that value repeatedly. I suspect that those of the colleague participants who gave this answer C have probably done a course in optimizing compilers. When you compile a C or C++ program, modern compilers optimize the code. What is the optimization? Compilers, when they translate our program instructions into machine instructions, compilers are also worried about generating instructions which are as efficient as possible. So, what the modern compilers do is they are able to identify iterations easily anyway. They look at any expression inside the deeper iteration and they analyze whether within the iteration the value of the concerned operands is changing or not changing. They find out very quickly that n is constant, n is not changing at all and therefore a compiler determines that look, I need not waste time in computing n into n every time. So, what the compiler does, what we did ourselves just now, I go back to this program, we actually replaced this n into n by n2 and put outside all these iterations a statement int n2 equal to n square. Compiler does this. Compiler actually generates an artificial variable, allocates it a location, calculates the value of n square, puts that result in n2 and wherever there is a reference to n square inside this, in this case it is only once, but there could be many. It will simply replace that reference, not by instructions which will compute the multiplication, but by a reference to a variable which has been so artificially created. Obviously, some of us may be teaching these in compiler courses or some of us may have studied it in the compiler courses. Since for most others who are playing good programmers and programming teachers without the knowledge of optimizing compilers it is hard to guess and that is the reason why c answer cannot be guessed unless it is known ahead of time. However, what is important is that even though I may not be able to guess the answer c correctly, I should be able to figure out that a and b are wrong. If I do not know optimizing compilers, my right response should be as a student, I do not know and also cannot guess. But if I know the compilers, c should be the correct answer and now look at what else can we do? Because we tried this, we replaced n square by some variable n2. Unfortunately, when we run the program with time command it still seems to be taking the same amount of time. So, the optimizing compiler had already stolen our brilliancy from us and we do not seem to have anything better. But as a good programmer we will not quit. We will say can we do something better? So, we examine this program again. We find that there is nothing much that we can do. Then we go back to the basic concept. What is the basic concept? This is the computation that is being done and this is the computation being done in the nested iteration. So, clearly I have to reduce this computation somehow. Now, this is repeated. I do not calculate n square again alright, but instead of considering the square we can consider only a triangle half of that square with area pi by 8 and this should reduce computations by half or even more. So, anyway here is an idea that instead of considering the square I can consider only a triangle. There is another modification that I can do here. If I do i equal to 1 to n and j equal to 1 to n, I am looking at all the points within the square. But if I do i equal to 1 to n and j equal to i 2 sorry j equal to i to n. So, I do not start j equal to 1. If i is 1 then j will start it. If i is 5 then I will start j with 5. Why? I am actually saying that I have a square which is symmetric around its diagonal. So, I can just calculate the triangle. Notice that by doing this I will be calculating either the upper triangle or lower triangle depending upon how you look at it. Since triangle is half of the square I am doing half the computations and it does not matter whether n square has been removed outside by the compiler or by me. But I do both these things. So, in short I have made just one modification here. But since I am calculating only half the area instead of multiplying it by 4 I have to multiply it by 8. Common sense my estimation technique remains sense I print the value of pi. Now I execute this version. If I execute it I have shown execution time only for 20,000 and 50,000. We do not remember the 20,000 times but if you see the time taken for executing this algorithm with n equal to 50,000. Please note that means I am examining 50,000 into 50,000 by half points. Now half because earlier I was examining 50,000 by 50,000. I am examining only points within the triangle. Now I see the user time is 13.461 seconds. You will recall earlier it was in the range of 26-27 seconds. It has indeed reduced by half. There is an appreciable reduction. Believe me doing this mara-mari for reducing the time amount by here, by there, etcetera, etcetera may not appear very relevant but I will tell you from my experience in the real world that our students who pass out and join companies and write programs do not have the efficiency of algorithm in their mind at all and therefore the programs that they write cause a lot of performance degradation in actual life. I have been a researcher in performance evaluation much of my earlier life and I can tell you from the industry interaction that I had that while people tend to blame the hardware is slow or people tend to say that the database is not performing very well. The fact of life is that 80 to 85 percent of the time if an application is not working properly at the desired speed the reason is bad application program. If you write those application programs the students whom you and I teach I would therefore submit that it is important for us to even formally get at least some elementary notion of efficiency introduced in the very first course in program. At IIT I have found that by this simple discussion in just one of the lectures people understand this and subsequently in the lab we tell them okay compile your program but run it with the time comma and see how long it takes and on the same machine we make different students programs run and compare against each other. So in general the habit of thinking about efficiency of the algorithm gets ingrained into them while they are writing their elementary programs. There is a little more to this notion I usually use this opportunity to talk to my first year students on some elementary concepts of time complexity. I say that there are two ways of looking at the time taken by a program to execute. One is the micro view that is the view that we just took. We look at the time taken by each instruction the program to execute number of times that instruction is executed that is how we said that if I if I calculate if I run an iteration n square time etc etc I am going to spend a lot of time computing. While the machine executes instructions in a few tens of microseconds or even in hundreds of nanoseconds every instruction takes a different amount of time depending upon its nature. So in micro view remember that we had addition takes more subtraction takes less etc etc although the thumb rules have varied over the last three decades of development of the computer hardware but in general if I define a unit time whether it is one microsecond or ten nanoseconds it does not matter but one unit time and then based on the computer's hardware and the software which is implemented by the compiler I find out how much time it takes to execute these different instructions I will get a funny statistics about the machine and the program behavior which will be my micro view at the smallest level. So this is an arbitrary thing I have written some hypothetical comparative execution time I consider assignment to take one unit then addition and subtraction takes two units time multiplication takes three units division takes five units comparison takes three units floating point operation as compared to integer operation takes five minutes five times the integer operation some arbitrary numbers I have given indeed even today for most of the machines you can actually get these types there used to be a very early benchmark which actually called MIPS or million instructions per second and what it did is based on such computations it decide defile a mix of instruction some addition some subtraction some multiplication some comparisons and how many of the instructions of that mix are executed per second used to decide the speed of the processor of the hardware and the first computer which cross one million instructions per second from that MIPS from that mix was called a very fast computer MIPS computer of course modern computers can do a billion instructions per second not million still in terms of the approach to the problem of analyzing computers performance this micro view holds some sense we can consider other operations which we have not yet studied such as reading from days or assignment to an array element these will take longer time in this workshop itself we are going to discuss arrays in the arrays and matrices over the next two days but in any case since most of your teachers you are aware of the arrays in my course I usually take this particular lecture after arrays have been introduced so let's go ahead with it I was saying that some operations such as reading from desk or assigning to an array element may take longer because in an array element I might have something like a three star i plus j equal to something now technically equal to something is merely an assignment operation it should take one unit of time but the computation of this index itself will take longer depending upon how many multiplication solutions I am doing of course all these operations are intrinsically done by the CPU a discrete operation would be thousand to ten thousand times costlier and generally people don't take that into account while calculating the efficiency of an algorithm in this sense finally we define the time complexity of an algorithm in this fashion suppose in our program there is an iteration which let us say execute n time where n is some input value now if the value of n largely determines the total amount of computation that is carried out by that algorithm then we can call this n as size of the problem notice how aptly this definition applies to the example that we are considering of estimating the value of phi there we saw very clearly that as n increases the execution time included and therefore n can be definitely called the representative size of the problem that like this further the number of computations which are required to execute the algorithm can now be expressed in terms of n which is the size of the problem for our pi calculations we know that the innermost iteration is executed either n-square time or n-square by two times or whatever but some and maybe there are some other computations like addition subtractions and so on so arbitrarily I might get an equation of the time 24 n-square plus 78 n plus 180 this constants are arbitrary they will depend they will change from hardware to hardware but roughly what we are saying is that if n is the size of the problem that my algorithm seems to take something a times n-square plus b times n plus c it is not difficult to arrive at such a formulation of computation time requirement of an algorithm this incidentally is a polynomial of degree 2 if I have many nested iterations a three level nested iteration then I might have some t n cube plus a n square plus b n plus c so I will have a polynomial where n will have a power of 3 what do these formulations and these constants mean in actual practice in actual practice if I want to compare two algorithms I have written one algorithm to calculate pi which has n-square by two iterations after this modification a colleague of mine somewhere else has written an algorithm which calculates that by splitting the problems around neatly and calculating something for 1.5 n times something else for etc etc whatever whatever it might appear arbitrary at this stage but those of you who have either studied or taught data structures and algorithms would know that in case of sorting even simple techniques could change the computational time requirement either by this amount or that amount and therefore these things are possible all that we are interested in telling our first year students to this example is a very simple thing that look in general by counting the number of multiplications additions etc you are doing and by looking at the size of the problem I can in general arrive at a formula with some constants which describes the total computation time that the whole algorithm will require what we are talking about is comparing two algorithms which have different execution times so when comparing two algorithms firstly we can get such expressions for each and then compare for specific values of n this is a good example in my opinion I take some arbitrary program called prog 1 and another arbitrary program called prog 2 these are nothing to do with prog 1 and prog 2 in our examples by this is just some programs which are trying to do the same thing but differently the algorithms are different imagine now that the time complexity of prog 1 is 24 n square plus 78 n plus 183 and imagine that the time complexity of prog 2 is 12,586 n plus 6,453 these are arbitrary examples but the point that I am making is there is a different equation which describes that that time complexity of an algorithm which is solving the same problem that the other one in this case it is 24 n square plus something n plus 183 in this case is a large number into n plus 6,453 if we compare these two expressions we notice that program 1 will run faster than program 2 up to a certain name it is very obvious that if n is 1 for example or n is 2 or n is 4 or n is 5 this expression will be much smaller than the second one but you can clearly say that since this is a quadratic and this is a linear equation and the linear curve grows much slower than the quadratic this will grow almost like like an exponent that means there will be some value of n some size of the problem beyond that size algorithm 2 that is prog 2 will always run faster than prog 1 although these constants are very high so we note that whenever we get expression for complexity of algorithm of this type then for all values of n greater than a certain threshold value an algorithm which has an expression with smaller degree of n will run faster in short this algorithm is more efficient than this there is a very cute and nice notation to represent this fact in the theory of computations and in time complexity the customary mechanism to compare algorithms is on the basis of their behavior when n is very large indeed what the theory says is you calculate these expressions and take the limit as n tends to infinity when n tends to infinity that means n becomes very large it is very obvious that the higher order term will predominant and therefore program 1 is said to be order n square written as o n square whereas program 2 is order n or order o n this is a standard way of describing mathematically the time complexity of an algorithm although often this is not in the syllabus but at one or two places I have seen the mention of time complexity my submission to collect teachers who are participating is that independent of whether it is in the syllabus or not the first part namely the ability to measure the execution time using utility such as time should be compulsorily taught to all of us students and at least for those who wish or who wonder ok how do I compare this algorithm you might either consider an extra lecture or why in a regular lecture tell them you do not ask any question in the examination this is generally for the benefit of their better understanding a very important concept is being told to our first year fresher students that the algorithms can be compared on the basis of their relative execution time and that when the problem size becomes large then their behavior in the limit when n tends to infinity is what is considered a determining factor which describes what we call the order or big notation these are all technical term so one algorithm is order n square another algorithm which is order n order n algorithm is always better if there is a algorithm which order n cube then that is always costlier than anything else in large problem solving such as sorting and searching these orders are very important so an algorithm for example which is order is faster than an algorithm which is order n order n might appear to be the first test if you look at this expression ok this is an order n algorithm what can be faster than this only an algorithm which takes fixed time there cannot be any algorithm which takes fixed time independent of the size of the problem so this appears to be faster but that is not so consider proc 3 now whose expression says k1 times log n plus k2 now if n increases linearly log n increases still slower and therefore you will find that that will be faster than this consequently order or big o notation order n square order n order log n etcetera etcetera are the kind of representations for algorithmic complexity and the conclusion that we draw is that in general our effort while writing our program should be a try to reduce the order of complexity so if there are n cube operation that are happening try to do that in n square operation or 5 times the n square operation so if you have three nested iterations try to see that by some intelligent jugglery you can remove those three nested iterations and do only two nested iterations but do a whole lot of additional computation it does not matter secondly if it is impossible to reduce the order of complexity then within the same order try to reduce the coefficients of expression please note that the last modification that we discussed on our program to estimate the value of pi falls in the second category let me just go back very quickly and tell you why I say that if I look at this program earlier I was varying j from 1 to n now I am varying j from i to n earlier I was doing n square iterations of this statement now I am doing n square by two iterations of that statement the order of complexity of this algorithm as compared to the earlier algorithm is same both are order n square but the factor constant if it was n times n square and this is k 2 times n square very clearly k 2 is half of k 1 where I have simply chopped off half the computation in real life I submit that it may not be possible for normal programming that we do both in colleges or even later in the real life to be able to devise algorithms which will change the order of complexity of the algorithm on a possible way however it is always possible always possible that any program that I have written if I examine it carefully I can always shave off a few unnecessary computations by intelligently tweaking the control structures or by shifting computing statements from here and there only thing is I must look for them and the fact is I will never look for them if as my teachers you never even suggested it to me when I was learning computer program that is the reason why I suggest that at least some introduction to the time complexity of the algorithm we may if we wish not call this time complexity and introduce theoretical concepts at all but at least the need to evaluate the performance by measuring the execution time should be conveyed to our students. I am sorry it is already one o clock thank you.