{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Complexity\n", "\n", "When writing programs, specially if one is dealing with a big amount of data, it is important to take care how fast the program runs. A small modification in an algorithm may bring execution time from hours to seconds. In computer science, the area that studies algorithm efficiency is called **complexity theory**. In this lecture, we learn how to reason about the efficiency of the programs we write.\n", "\n", "Let's start with an example. Both functions below compute the sum of numbers from 1 to n." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def sum1(n):\n", " s = 0\n", " for i in range(n):\n", " s += (i+1)\n", " return s\n", "\n", "def sum2(n):\n", " s = (n * (n + 1)) // 2\n", " return s" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "How fast do they run?\n", "\n", "Since we can plot graphs now, let's plot the graph of how long it takes for each function to run, as a function of n." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAm8AAAFpCAYAAADKh88IAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4yLCBo\ndHRwOi8vbWF0cGxvdGxpYi5vcmcvhp/UCwAAIABJREFUeJzs3XmYFNW9PvD3OzMMi2zKosgiEHEB\n1BgRNS5xB5crGpeAGxEjLrjEJa5xuUbixZu4L78orsSISrxCIlejojESBUaNyJ4RkUXWAQZkGJjl\n/P741rldXVPdXb13db+f5+Hp7urqU6e6p2dezqlzjhhjQEREREThUJbvChARERFRcAxvRERERCHC\n8EZEREQUIgxvRERERCHC8EZEREQUIgxvRERERCHC8EZEREQUIgxvRERERCHC8EZEREQUIgxvRERE\nRCFSke8KZFPXrl1N3759810NIiIiooQ+++yzDcaYbon2K+rw1rdvX1RVVeW7GkREREQJici3QfZj\ntykRERFRiDC8EREREYUIwxsRERFRiDC8EREREYUIwxsRERFRiDC8EREREYUIwxsRERFRiDC8ERER\nEYUIwxsRERFRiDC8EREREYUIwxsRERFRiDC8ERERUenYsgVYtSrftUgLwxsRERGVjgMPBHr1ynct\n0sLwRkRERKXj22/zXYO0MbwRERERhQjDGxEREVGIBApvIjJcRBaLSLWI3OrzfGsRedV5fpaI9HU9\nd5uzfbGIDEtUpohc7WwzItLVtf0CEZkrIl+JyD9F5KBUT5qIiIgorBKGNxEpB/AEgFMADAQwSkQG\nena7FMAmY8zeAB4CMMF57UAAIwEMAjAcwJMiUp6gzJkATgTg7ZT+BsBPjDEHAPgNgKeTPFciIiKi\n0AvS8jYUQLUxZqkxZieAyQBGePYZAeBF5/4UACeIiDjbJxtjdhhjvgFQ7ZQXs0xjzBfGmGXeShhj\n/mmM2eQ8/BRAuIeKEBEREaUgSHjrCWCF6/FKZ5vvPsaYRgC1ALrEeW2QMuO5FMD/JrE/ERERUVGo\nyHcFkiUix0HD21Exnh8LYCwA9OnTJ4c1IyIiIsq+IC1vqwD0dj3u5Wzz3UdEKgB0AlAT57VBymxB\nRA4EMBHACGNMjd8+xpinjTFDjDFDunXrlqhIIiIiolAJEt7mABggIv1EpBI6AGGaZ59pAEY7988B\n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\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import time\n", "import matplotlib.pyplot as plt\n", "\n", "plt.figure(figsize=(10,6))\n", "\n", "xs = []\n", "ys = []\n", "for i in range(1000):\n", " t0 = time.time()\n", " s = sum1(i)\n", " t1 = time.time()\n", " t = t1 - t0\n", " xs += [i]\n", " ys += [t]\n", " \n", "plt.plot(xs, ys, 'r')\n", "\n", "xs = []\n", "ys = []\n", "for i in range(1000):\n", " t0 = time.time()\n", " s = sum2(i)\n", " t1 = time.time()\n", " t = t1 - t0\n", " xs += [i]\n", " ys += [t]\n", " \n", "plt.plot(xs, ys, 'b')\n", "\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If you needed a fast function for adding numbers from 1 to n, which one would you choose? It is clear that `sum2` is better. That is because, as n grows, the *running time* of `sum2` remains more or less constant, while the running time of `sum1` grows as n grows.\n", "\n", "In practice, we are not worried exactly about how fast the code runs for a particular input, but **how much slower it gets as the input grows**. \n", "\n", "Ideally, we would all like to have code that behaves as `sum2`, i.e., the running time is more or less constant regardless of the input size. But more often than not, algorithms take longer to run as the input grows. It is important to be able to understand how the input size affects our code, and we don't have to plot graphs to do that each time. Instead, we perform the **complexity analysis** of the code.\n", "\n", "## Complexity analysis\n", "\n", "There are two important parts of a complexity analysis: *computing the number of steps* and *deciding what is the input size*.\n", "\n", "### Computation steps\n", "\n", "The efficiency of a program is measured by counting the number of steps it takes to reach a solution. Each atomic computation operation counts as one step. These include:\n", "\n", "- Assignment (e.g. `L = []`)\n", "- Arithmetic operations (e.g. `x + y`)\n", "- Boolean comparisons (e.g. `c == 't'`)\n", "- Indexing (e.g. `L[i]`)\n", "\n", "What are the number of steps `sum1` and `sum2` take for n = 5?" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "n: 5 steps: 16\n", "n: 5 steps: 4\n" ] }, { "data": { "text/plain": [ "15" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "def sum1_steps(n):\n", " s = 0\n", " steps = 1\n", " for i in range(n):\n", " s += (i+1)\n", " steps += 3\n", " print(\"n:\", n, \" steps:\", steps)\n", " return s\n", "\n", "def sum2_steps(n):\n", " s = (n * (n + 1)) // 2\n", " steps = 4\n", " print(\"n:\", n, \" steps:\", steps)\n", " return s\n", "\n", "sum1_steps(5)\n", "sum2_steps(5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Input size\n", "\n", "Since we want to analyse how our program behaves as the input grows, we need to decide on **what it is about the input that affects the number of steps**. \n", "\n", "For the `sum1` function, the larger n is, the more times the loop is run, which incurs on 3 extra steps. So the actual value n is a good input measure. The number of steps can be computed by f(n) = 3*n + 1.\n", "\n", "For the `sum2` function, no matter how large n is, it will take the same amount of time. So this function is independent of input. Another way of seeing this is: regardless of the input size we choose, the function takes constant time. The number of steps is f(n) = 4.\n", "\n", "Sometimes, more than one input size will affect how the code runs, and that's ok. That simply means that the number of steps will be a function of two values.\n", "\n", "Take the function `myCount` below. What would you use as the input size?" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "def myCount(e, L):\n", " c = 0\n", " for x in L:\n", " if x == e:\n", " c += 1\n", " return c" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The number of steps this function takes will depend on the number of times the loop runs, which, in turn, depends on the number of elements in `L`. A reasonable input size then is the *number of elements in L*. Note that the input `e` does not play a role on the number of steps, and so we can safely ignore it for the input measure.\n", "\n", "What about the `isIn` function? What would be its input size?" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def isIn(e, L):\n", " for x in L:\n", " if e == x:\n", " return True\n", " return False" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You might have noticed that there is something different about the `isIn` function. The number of steps it will take not only depends on the number of elements in the list `L` but on *where* element `e` is in `L` (if anywhere). Taking this kind of details into account will quickly become too overwhelming or specific. Think, for example, on sorting algorithms. Depending on the algorithm, the number of steps it performs depends on how many elements are out of order.\n", "\n", "That is why, when it comes to complexity analysis, we will only be worried about the **worst case scenario:** there one in which the function will take the most amount of steps. By being as pessimistic as possible, we are safe that the program will not take longer to run, and if it runs faster, all the better.\n", "\n", "Finding the balance of what we can abstract away and what needs to be taken into account might sound complicated. It helps sometimes to think of the extremes. On one end, we are overly worried about the exact number of steps and this will depend on all sorts of details of the input, which will get out of hand and too complicated to handle. On the other hand, we abstract away too many details, and just choose a ridiculous amount of steps as our upper bound. Certainly the program will take fewer than that, but this is not at all informative of the running time. (If I tell you your final grades will be out by December this year, it is a true statement, but not really helpful.)\n", "\n", "Fow our `isIn` function above, the worst case is when `e` is not in `L` at all. In which case it runs through all iterations of the loop, without ending prematurely. And what determines how many times the loop runs is the length of `L`, so that is the input size used for complexity analysis.\n", "\n", "## Big-O notation\n", "\n", "There is yet one more abstraction we can make. We are interested in how much the running time grows as the input increases. If we plot the graph for running time, this measure is represented by how *steep* this curve is. Suppose we have measures of steps for two functions:\n", "\n", "f(n) = 2*n + 10\n", "\n", "g(n) = n + 1000\n", "\n", "Which one is worse? Which one has a faster growth rate as n increases? Let's plot them and see." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "xs = []\n", "ys = []\n", "for n in range(10000):\n", " xs += [n]\n", " y = 2*n + 10\n", " ys += [y]\n", " \n", "plt.plot(xs,ys,'r')\n", "\n", "xs = []\n", "ys = []\n", "for n in range(10000):\n", " xs += [n]\n", " y = n + 1000\n", " ys += [y]\n", " \n", "plt.plot(xs,ys,'b')\n", "\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Even though function f grows more, they are both *linear* functions. That means that runtime will increase linearly with n. In other words, if n increased by 10, the runtime will increase by a factor of 10, regardless of whether this increase was from 10 to 20 or from 500 to 510. That's a good thing about linear functions, they don't grow too fast.\n", "\n", "However, see what happens when we compare f with the function h:\n", "\n", "h(n) = n$^2$ + 2" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "xs = []\n", "ys = []\n", "for n in range(1000):\n", " xs += [n]\n", " y = 2*n + 10\n", " ys += [y]\n", " \n", "plt.plot(xs,ys,'r')\n", "\n", "xs = []\n", "ys = []\n", "for n in range(1000):\n", " xs += [n]\n", " y = n*n + 2\n", " ys += [y]\n", " \n", "plt.plot(xs,ys,'b')\n", "\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Surprisingly, function h grows so fast, that f looks like a constant function (although we know it is not!).\n", "\n", "That is because h is a *quadratic* function. Differently from a linear function, increasing the input size from 500 to 510 will cause a much much higher increase in runtime than increasing the input size from 10 to 20.\n", "\n", "When analysing program complexity, we are only worried on how fast running time grows with the growth of input, so the important part of all of those functions is the *dominating factor*.\n", "\n", "The big-O notation describes functions' asymptotic behavior (i.e. its dominating factor, or how fast it grows, or how steep its curve it). For the functions above, we say that f is $O(n)$, and h is $O(n^2)$ (read \"big oh of n squared\" -- or quadratic). Typically, the complexity of algorithms will fall in one of these common complexities (in decreasing speed):\n", "\n", "- $O(1)$: constant (e.g. if $f(n) = 4$ then $f$ is $O(1)$). This is the fastest you can get.\n", "- $O(\\log n)$: logarithmic\n", "- $O(\\sqrt{n})$: square root\n", "- $O(n)$: linear (e.g. if $f(n) = 10n + 2$ then $f$ is $O(n)$). This is generally still considered good.\n", "- $O(n \\log n)$: linearithmic, loglinear or quasilinear\n", "- $O(n^2)$: quadratic\n", "- $O(n^3)$: cubic\n", "- $O(n^k)$: polynomial\n", "- $O(k^n)$: exponential (e.g. if $f(n) = 2^{4n}$ then $f$ is $O(2^n)$). This is generally considered slow.\n", "- $O(n!)$: factorial. Algorithms falling in this category cannot usually be used in practice for really big $n$.\n", "\n", "By comparing the asymptotic behavior of two programs, we can identify which one behaves best when the input size is increased. The following graph gives us an idea of how different functions compare:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "image/png": "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\naQAAAABJRU5ErkJggg==\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import math\n", "\n", "xs = []\n", "ys = []\n", "for n in range(1,30):\n", " xs += [n]\n", " y = 50\n", " ys += [y]\n", " \n", "plt.plot(xs, ys, 'r', label='constant')\n", "\n", "xs = []\n", "ys = []\n", "for n in range(1,30):\n", " xs += [n]\n", " y = 400*math.log(n)\n", " ys += [y]\n", " \n", "plt.plot(xs, ys, 'b', label='logarithmic')\n", "\n", "xs = []\n", "ys = []\n", "for n in range(1,30):\n", " xs += [n]\n", " y = 100*n\n", " ys += [y]\n", " \n", "plt.plot(xs, ys, 'g', label='linear')\n", "\n", "xs = []\n", "ys = []\n", "for n in range(1,30):\n", " xs += [n]\n", " y = 5*n*n\n", " ys += [y]\n", " \n", "plt.plot(xs, ys, 'c', label='quadratic')\n", "\n", "xs = []\n", "ys = []\n", "for n in range(1,30):\n", " xs += [n]\n", " y = math.pow(2,n)\n", " ys += [y]\n", " \n", "plt.plot(xs, ys, 'm', label='exponential')\n", "\n", "plt.legend(loc=\"upper right\")\n", "plt.ylim((0,2000))\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Built-in functions\n", "\n", "We can consider \"native\" operations to take a constant amount of time, but most of the *built-in* python functions will have a complexity greater than constant. Take for example the `count` function.\n", "\n", "The two codes below count the number of occurrences of elements in a list `L` and returns this information in a dictionary. Although both seem \"linear\" (one loop over `L`), `count1` has some hidden work in the call to the `count` function. See how their runtime graphs behave." ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def count1(L):\n", " d = {}\n", " for e in L:\n", " c = L.count(e)\n", " d[e] = c\n", " return d\n", " \n", "def count2(L):\n", " d = {}\n", " for e in L:\n", " if e in d:\n", " d[e] += 1\n", " else:\n", " d[e] = 1\n", " return d" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "image/png": "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\nREQEgP8PVXLrlg3VS8EAAAAASUVORK5CYII=\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import random\n", "\n", "def genList(n):\n", " L = []\n", " for i in range(n):\n", " x = random.randint(1,1000)\n", " L += [x]\n", " return L\n", "\n", "xs = []\n", "ys = []\n", "for i in range(1000):\n", " L = genList(i)\n", " t0 = time.time()\n", " s = count1(L)\n", " t1 = time.time()\n", " t = t1 - t0\n", " xs += [i]\n", " ys += [t]\n", " \n", "plt.plot(xs, ys, 'r')\n", "\n", "xs = []\n", "ys = []\n", "for i in range(1000):\n", " L = genList(i)\n", " t0 = time.time()\n", " s = count2(L)\n", " t1 = time.time()\n", " t = t1 - t0\n", " xs += [i]\n", " ys += [t]\n", " \n", "plt.plot(xs, ys, 'b')\n", "\n", "plt.show()\n", " " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It turns out `count1` is actually *quadratic*. That is because of the `for` loop with `count` inside. `count` executes linearly on the size of the list, so what we have is:\n", "\n", "```\n", "# n is len(L)\n", "for e in L: # runs at most n times\n", " c = L.count(e) # runtime linear with respect to n, so takes a*n + b steps for some a and b\n", " d[e] = c\n", "```\n", "\n", "That means the inner count will take $a*n + b$ steps, and that will run $n$ times (because of the outer loop). So this piece of code runs in $n*(a*n + b) = a*n*n + b*n \\in O(n^2)$.\n", "\n", "It is the same if we unfold the `count` function into its actual code, instead of calling it:\n", "\n", "```\n", "# n is len(L)\n", "for e in L: # runs at most n times\n", " c = 0\n", " for x in L: # runs at most n times\n", " if x == e:\n", " c += 1\n", " d[e] = c\n", "```\n", "\n", "This code also runs in $O(n^2)$.\n", "\n", "**Remark:** The python built-in `in` command on lists and strings runs in linear time as well. If it is used for dictionaries, it runs in constant time.\n", "\n", "Suppose the nested loops were such that the lists had different sizes:" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def countFrom(L1, L2):\n", " d = {}\n", " for e1 in L1:\n", " c = 0\n", " for e2 in L2:\n", " if e2 == e1:\n", " c += 1\n", " d[e1] = c\n", " return d" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Assume that $n$ is the length of `L1` and $m$ is the length of `L2`. Then, the outer loop runs $n$ times, and, for each of them, the inner loop runs $m$ times. That gives us a complexity of $O(n*m)$.\n", "\n", "If the loops were running one after the other, then we have a different situation:" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def countBoth(L1, L2):\n", " d = {}\n", " \n", " for e in L1:\n", " if e in d:\n", " d[e] += 1\n", " else:\n", " d[e] = 1\n", " \n", " for e in L2:\n", " if e in d:\n", " d[e] += 1\n", " else:\n", " d[e] = 1\n", " \n", " return d" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In that case, the first loop will run $n$ times, and once it is done the second loop starts and runs $m$ times. In that case, the complexity class is $O(n+m)$." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.3" } }, "nbformat": 4, "nbformat_minor": 2 }