{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Module 2, Practical 3\n", "\n", "In this practical we will start working with algorithm complexity through practical examples.\n", "\n", "## Complexity \n", "\n", "The *complexity* of an algorithm can be defined as a function mapping the size of the input to the time required to get the result. This is also called the *cost function*.\n", "\n", "There exist several asymptotic (time-measuring) notations. Informally they are:\n", "\n", "- Big Omega (best case)\n", "- Big Theta (average case)\n", "- Big O (worst case)\n", "\n", "The upper-bound complexity *O* (the *big-Oh*) is generally the most interesting to analyze. In this practical we will work with this notation considering several Python code samples.\n", "\n", "Big O is a formal notation that describes the behaviour of a function when the argument tends towards the maximum input. Big O takes the upper bound, that is, it considers the worst-case results, the worst execution of the algorithm. \n", "\n", "Instead of saying the input is 10 billion, or infinite, we say the input is ```n``` size. The exact size of the input doesn’t matter, we only care of how our algorithm performs with the worst input. This approach allows to still work with Big O even if we do not know the exact size of the input during the code execution.\n", "\n", "Big O is easy to read once we learn the different order of growth:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "image/png": "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g2EYTJs2jd69exMXF8fgwYP54YcfIvmWRESkCXmr/ezY3LzGvwDE9oUQGolpmvi9wYjs2+awYBjGEbefPHkyf/vb33jxxRfp0qULX375JVdffTVt2rThjTfeoFevXkyZMoVx48YxevRo2rZtGw4wtW6++WaefvppsrKyuP3227nwwgtZs2YNdnvszwsgIiL1Fa0rxQyaJLeKIzk9LtLlNBoFGMDvDfLyuLkR2ffvnz4Tu9N6RG09Hg8PP/wwX3zxBUOGDAGgU6dOfPXVV7z00ku88847vPTSS4wcOZKioiI+++wzvv32W2y2+j/me+65h/POOw+AN954g9zcXD788EN+9atfNe6bExGRiAuPf2lGvS/QwENIL7zwAr1798blcuFyuRgyZAjTp08Pr6+urmbMmDG0atWKpKQkLr30UrZv315vG5s2bWLEiBEkJCSQkZHBzTffjN/vr9dmzpw59OvXD6fTSefOnZk6derRv8Nm5Mcff6SyspLzzjuPpKSk8O3NN99k3bp1AFx++eX88pe/5JFHHuEvf/kLXbp02W87teEHID09nW7durFq1arj9j5EROT4aa4BpkE9MLm5uTzyyCN06dIF0zR54403uOiii/j222858cQTmTBhAtOmTeODDz4gJSWFsWPHcskllzBv3jwAAoEAI0aMICsri6+//ppt27YxcuRI7HY7Dz/8MADr169nxIgRjB49mrfffptZs2bx29/+luzsbPLz8xv/EyB0GOf3T5/ZJNs+kn0fqfLy0DHMadOm0bZt23rrnM7QaXGVlZUsWbIEq9XK2rVrG69QERGJOX5vgO0b3EDzCzCYxygtLc3861//apaUlJh2u9384IMPwutWrVplAub8+fNN0zTNzz77zLRYLGZRUVG4zQsvvGC6XC7T4/GYpmmat9xyi3niiSfW28evf/1rMz8/v0F1lZaWmoBZWlq637qqqipz5cqVZlVVVYO2GWlut9t0Op3mm2++edA2o0ePNrt3727+5z//MW02mzlr1qzwuv/+978mYL733nvhZbt37zYTEhLqLYs1sfrzFBFpaltW7zaf/X+zzNdv+Z8ZDAYjXc4ROdT3d11HPQYmEAjwwQcfUFFRwZAhQ1iyZAk+n4+hQ4eG23Tv3p127doxf/58Bg8ezPz58+nVqxeZmZnhNvn5+dxwww2sWLGCvn37Mn/+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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import math\n", "import pandas as pd\n", "import matplotlib.pyplot as plt\n", "\n", "inputList = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]\n", "\n", "linear = [n for n in inputList]\n", "logn = [math.log(n) for n in inputList]\n", "quadratic = [n*n for n in inputList]\n", "cubic = [n*n*n for n in inputList]\n", "exponential = [2**n for n in inputList]\n", "\n", "functDict = {'linear': linear, \"logn\": logn, \"quadratic\": quadratic, \"cubic\": cubic, \"exp\": exponential}\n", "functDf = pd.DataFrame(functDict) \n", "functDf.plot()\n", "plt.show()\n", "plt.close()\n", "\n", "\n", "functDf[[\"linear\", \"logn\", \"quadratic\"]].plot()\n", "plt.title(\"zoomed in\")\n", "plt.show()\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "\n", "##### Python built-in data structures and relative methods have different time complexity. A comprehensive list is available at this [link](https://wiki.python.org/moin/TimeComplexity)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Example 1**\n", "\n", "Determine the complexity of these two functions:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "4\n", "5\n", "6\n", "8\n", "---------------------\n", "Forward:\n", "4\n", "5\n", "6\n", "8\n", "Reverse:\n", "8\n", "6\n", "5\n", "4\n" ] } ], "source": [ "def printList(inputList):\n", " for item in inputList:\n", " print(item)\n", "\n", "printList([4, 5, 6, 8])\n", "\n", "print(\"---------------------\")\n", "\n", "def printListBothDirections(inputList):\n", " print(\"Forward:\")\n", " for item in inputList:\n", " print(item)\n", " print(\"Reverse:\")\n", " for item in inputList[::-1]:\n", " print(item)\n", "\n", "printListBothDirections([4, 5, 6, 8])\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
Show/Hide Complexity\n", "\n", "Both ```printList``` and ```printListBothDirections``` are ```O(n)```, so their complexity is linear with respect to the processed list lenght. \n", "To be precise, ```printListBothDirections``` is ```O(n+n) = O(2n)```, but since we're looking \n", "towards infinite-size inputs, the double of infinite is still infinite.\n", "\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Example 2**\n", "\n", "Determine the complexity of a function that computes the highest value for each pair of values from two input lists ```l1``` and ```l2```." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Value 4 in l1 greater than value 1 in l2\n", "Value 5 in l1 greater than value 1 in l2\n", "Value 6 in l1 greater than value 1 in l2\n", "Value 8 in l1 greater than value 1 in l2\n" ] } ], "source": [ "def computeHighest(l1, l2):\n", " for i1 in l1:\n", " for i2 in l2:\n", " if i1 > i2:\n", " print(\"Value {} in l1 greater than value {} in l2\".format(i1, i2)) \n", "\n", "computeHighest([4, 5, 6, 8], [12,1,42,11])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
Show/Hide Complexity \n", "\n", "The function is quadratic, ```O(n^2)```, as we do n iterations (one per each element in l1) times n iterations (one per each element in l2).\n", "\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Example 3**\n", "\n", "Determine the complexity of the following functions, performing multiple tasks." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "4 seconds left\n", "3 seconds left\n", "2 seconds left\n", "1 seconds left\n", "boom!\n", "--------------\n", "4>5>6>8>12>14\n", "--------------\n", "I'm in the diagonal 4 4\n", "I'm in the diagonal 5 5\n", "I'm in the diagonal 6 6\n", "I'm in the diagonal 8 8\n", "I'm in the diagonal 12 12\n", "I'm in the diagonal 14 14\n" ] } ], "source": [ "def myFunction(items):\n", "\n", " for i in reversed(range(1, 5)):\n", " print (\"{} seconds left\".format(i))\n", " print(\"boom!\\n--------------\")\n", "\n", " itemsString = \"\"\n", " for item in items:\n", " itemsString += \">{}\".format(item)\n", " print(itemsString[1:])\n", "\n", " print(\"--------------\")\n", "\n", " pairwiseProducts = []\n", " for item1 in items:\n", " for item2 in items:\n", " if (item1 == item2):\n", " print(\"I'm in the diagonal {} {}\".format(item1, item2))\n", " pairwiseProducts.append(item1*item2)\n", "\n", "myFunction([4, 5, 6, 8, 12, 14]) " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
Show/Hide Complexity \n", "\n", "The complexity of this function can be determined by breaking it down in its different parts:\n", "\n", "- the first loop does 4 iterations, regardless of the input. It is constant, so ```O(4)```.\n", "- the second loop does n iterations, where n is the size of the input. It is linear, so ```O(n)```.\n", "- the last loop does n*n iterations, where n is the size of the input. It is quadratic, so ```O(n^2)```. \n", "\n", "Therefore, by summing ```O(5) + O(n) + O(n^2)``` we can say that the function is ```O(n^2)```, which \"dominates\" the other terms.\n", "\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Example 4**\n", "\n", "Determine the complexity of the ```listHalver``` function that returns every division by 2 of the ```inputList``` parameter until it's empty, and the ```sliceStepper``` function that uses ```listHalver``` function with lists of length ```n...1```. " ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "11\n", "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n", "10\n", "[1, 2, 3, 4, 5, 6, 7, 8, 9]\n", "9\n", "[1, 2, 3, 4, 5, 6, 7, 8]\n", "8\n", "[1, 2, 3, 4, 5, 6, 7]\n", "7\n", "[1, 2, 3, 4, 5, 6]\n", "6\n", "[1, 2, 3, 4, 5]\n", "5\n", "[1, 2, 3, 4]\n", "4\n", "[1, 2, 3]\n", "3\n", "[1, 2]\n", "2\n", "[1]\n", "1\n", "[]\n" ] } ], "source": [ "for step in reversed(range(1, 12)):\n", " print(step)\n", " print(list(range(1, step)))" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[1, 2, 3, 4]\n", "[1, 2]\n", "[1]\n", "------------\n", "[1, 2, 3, 4, 5]\n", "[1, 2]\n", "[1]\n", "[1, 2, 3, 4]\n", "[1, 2]\n", "[1]\n", "[1, 2, 3, 4]\n", "[1, 2]\n", "[1]\n", "[1, 2, 3]\n", "[1]\n", "[1, 2, 3]\n", "[1]\n", "[1, 2]\n", "[1]\n", "[1, 2]\n", "[1]\n", "[1]\n", "[1]\n" ] } ], "source": [ "def listHalver(inputList):\n", " sliced = inputList\n", " while len(sliced) >= 2:\n", " sliced = sliced[:int(len(sliced)/2)]\n", " print(sliced)\n", "\n", "listHalver([1, 2, 3, 4, 5, 6, 7, 8, 9])\n", "print(\"------------\")\n", "\n", "def halverStepper(maxListLength):\n", " for step in reversed(range(1, maxListLength)):\n", " listHalver(list(range(1, step)))\n", "\n", "halverStepper(12)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
Show/Hide Complexity\n", "\n", "The ```listHalver``` function needs to look at a smaller subset of the data at every step, and is therefore logarithmic, ```O(log(n))```. \n", "The ```halverStepper``` function does ```n``` times an ```O(log(n))``` operation (```listHalver```), and is therefore ```O(nlog(n))```.\n", "\n", "\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Exercises\n", "\n", "1. Let ```M``` be a square matrix - a list containing ```n``` lists, each of them of size ```n```. Return the computational complexity of function ```fun()``` with respect to ```n```:\n", "\n" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [], "source": [ "def fun(M):\n", " for row in M:\n", " for element in row:\n", " print(sum([x for x in row if x != element]))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
Show/Hide Complexity\n", "\n", "```O(n^3)```, because the complexity is ```n``` for the list comprehension, times ```n``` for the inner ```for``` cycle, times ```n``` for the outer ```for``` cycle\n", "\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "2. Given a list ```L``` of ```n``` elements, please compute the asymptotic computational complexity of the following function, explaining your reasoning." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def my_fun(L):\n", " n = len(L)\n", " tmp = []\n", " for i in range(int(n)):\n", " tmp.insert(0,L[i]-L[int(n/3)])\n", " return sum(tmp)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
Show/Hide Complexity\n", "\n", "It mainly depends on the implementation of the list (we will see in the following practicals what this means). One possbile answer could be:\n", "\n", "- ```len(L)``` has a constant complexity ```O(1)```\n", "- the for loop costs ```n``` times the head insertion in the list ```tmp```, if this requires a shift right of all the previously inserted elements, this could be in total ```O(n^2)```\n", "- the final sum costs ```O(n)```\n", "\n", "This makes a quadratic overall asymptotic complexity.\n", "\n", "
\n", "\n", "3. Given a sorted list ```alist``` of ```n``` elements, please compute the asymptotic computational complexity of the following function implementing binary search, explaining your reasoning." ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [], "source": [ "def binarySearch(alist, item):\n", " first = 0\n", " last = len(alist)-1\n", " found = False\n", "\n", " while first <= last and not found:\n", " midpoint = (first + last)//2\n", " if alist[midpoint] == item:\n", " found = True\n", " else:\n", " if item < alist[midpoint]:\n", " last = midpoint-1\n", " else:\n", " first = midpoint+1\n", "\n", " return found" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
Show/Hide Complexity\n", "\n", "The binary search divides by two the lenght of the list at each iteration, this maks the asymptotic complexity to be ```0(log(n))```.\n", "\n", "
\n", "\n", "4. Please compute the asymptotic computational complexity of the following code, that computes the Fibonacci sequence according to the following formula:\n", "\n", "- If ```n``` is even, then ```k = n/2``` and ```F(n) = [2*F(k-1) + F(k)]*F(k)```\n", "- If ```n``` is odd, then ```k = (n + 1)/2``` and ```F(n) = F(k)*F(k) + F(k-1)*F(k-1)```." ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0 1 1 2 3 5 8 13 21 34 \n" ] } ], "source": [ "# Create an array of length n for memoization (we will see later what memoization is...)\n", "n = 10\n", "f = [0] * n\n", " \n", "# Returns n'th fibonacci number using table f[]\n", "def fib(n) :\n", " # Base cases\n", " if (n == 0) :\n", " return 0\n", " if (n == 1 or n == 2) :\n", " f[n] = 1\n", " return (f[n])\n", " \n", " # If fib(n) is already computed (thanks to memoization)\n", " if (f[n]):\n", " return f[n]\n", " \n", " # Applying above formula [Note value n&1 is 1\n", " # if n is odd, else 0.\n", " if((n & 1)):\n", " # (n & 1) is 1 when n is odd, 0 otherwise\n", " k = (n + 1) // 2\n", " f[n] = (fib(k) * fib(k) + fib(k-1) * fib(k-1))\n", " else :\n", " k = n // 2\n", " f[n] = (2*fib(k-1) + fib(k))*fib(k)\n", " \n", " return f[n]\n", " \n", " \n", "# main code\n", "for i in range(n):\n", " print(fib(i), end=' ') # avoids to add a new line at each iteration\n", "print('') # to go to new line at the end" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
Show/Hide Complexity\n", "\n", "Thanks to memoization, the access to the already computed Fibonacci numbers has constant complexity (```O(1)```). This makes the asymptotic complexity of the function ```fib``` to be logarithmic (```O(log (n))```). The function ```fib``` is then called ```n``` times. This makes the overall complexity to be ```O(n log(n))```. This algorithm utilizes the Fast Doubling method to achieve logarithmic time complexity (O(logn)), requiring only roughly log2​n steps to compute the result because it recursively cuts the problem size in half at every stage. See [here for more details](https://www.nayuki.io/page/fast-fibonacci-algorithms).\n", "\n", "
\n", "\n", "5. Please compute the asymptotic computational complexity of the function ```subsets```, that computes all the subsets of a set of elements.\n", "\n", "```\n", "Subsets of {a,b}: {(), ('b',), ('a',), ('b', 'a')}\n", "Subsets of {a,b,c}: {(), ('b',), ('a',), ('c',), ('b', 'a'), ('b', 'c'), ('a', 'c'), ('b', 'a', 'c')}\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from itertools import chain, combinations\n", "\n", "def subsets(elementSet):\n", " return set(chain.from_iterable(combinations(elementSet, r) for r in range(len(elementSet)+1)))\n", "\n", "print('Subsets of {a,b}:', subsets({'a','b'}))\n", "print('Subsets of {a,b,c}:', subsets({'a','b','c'}))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
Show/Hide Complexity\n", "\n", "What’s important to notice here is that the number of subsets grows **exponentially** with the number ```n``` of the elements on the original set. This makes the overall complexity to be exponential ```O(2^n)```.\n", "\n", "
" ] } ], "metadata": { "celltoolbar": "Edit Metadata", "kernelspec": { "display_name": "3.10.14", "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.10.14" } }, "nbformat": 4, "nbformat_minor": 2 }