diff options
| author | Sebastiano Tronto <sebastiano.tronto@gmail.com> | 2021-05-25 17:10:49 +0200 |
|---|---|---|
| committer | Sebastiano Tronto <sebastiano.tronto@gmail.com> | 2021-05-25 17:10:49 +0200 |
| commit | d6c61d988bfa4255baf9cdae42db59ebee38363f (patch) | |
| tree | 118ff3c2424e735149c145524965a4a337e50beb /src/Lecture7/slides/.ipynb_checkpoints/X1-ComputationalComplexity-notebook-checkpoint.ipynb | |
| parent | 46eef66b1e1571c77dc828d7e950b129b4c8bfd0 (diff) | |
| download | mathsoftware-d6c61d988bfa4255baf9cdae42db59ebee38363f.tar.gz mathsoftware-d6c61d988bfa4255baf9cdae42db59ebee38363f.zip | |
Added files
Diffstat (limited to '')
| -rw-r--r-- | src/Lecture7/slides/.ipynb_checkpoints/X1-ComputationalComplexity-notebook-checkpoint.ipynb | 412 |
1 files changed, 412 insertions, 0 deletions
diff --git a/src/Lecture7/slides/.ipynb_checkpoints/X1-ComputationalComplexity-notebook-checkpoint.ipynb b/src/Lecture7/slides/.ipynb_checkpoints/X1-ComputationalComplexity-notebook-checkpoint.ipynb new file mode 100644 index 0000000..16a6d40 --- /dev/null +++ b/src/Lecture7/slides/.ipynb_checkpoints/X1-ComputationalComplexity-notebook-checkpoint.ipynb | |||
| @@ -0,0 +1,412 @@ | |||
| 1 | { | ||
| 2 | "cells": [ | ||
| 3 | { | ||
| 4 | "cell_type": "markdown", | ||
| 5 | "metadata": {}, | ||
| 6 | "source": [ | ||
| 7 | "# Nested loops\n", | ||
| 8 | "\n", | ||
| 9 | "The following two functions compute sum and product of matrices, respectively.\n", | ||
| 10 | "\n", | ||
| 11 | "By counting the nested loops it is easy to see that `add()` is $O(n^2)$ while `prod()` is $O(n^3)$." | ||
| 12 | ] | ||
| 13 | }, | ||
| 14 | { | ||
| 15 | "cell_type": "code", | ||
| 16 | "execution_count": 2, | ||
| 17 | "metadata": {}, | ||
| 18 | "outputs": [ | ||
| 19 | { | ||
| 20 | "name": "stdout", | ||
| 21 | "output_type": "stream", | ||
| 22 | "text": [ | ||
| 23 | "Time for add: 0.005766554000000035\n", | ||
| 24 | "Time for prod: 1.3871021639999999\n" | ||
| 25 | ] | ||
| 26 | } | ||
| 27 | ], | ||
| 28 | "source": [ | ||
| 29 | "from random import randint\n", | ||
| 30 | "import time\n", | ||
| 31 | "\n", | ||
| 32 | "def add(A, B):\n", | ||
| 33 | " S = [[0] * len(A) for i in range(len(A))]\n", | ||
| 34 | " for i in range(len(A)):\n", | ||
| 35 | " for j in range(len(A)):\n", | ||
| 36 | " S[i][j] = A[i][j] + B[i][j]\n", | ||
| 37 | " return S\n", | ||
| 38 | "\n", | ||
| 39 | "def prod(A, B):\n", | ||
| 40 | " S = [[0] * len(A) for i in range(len(A))]\n", | ||
| 41 | " for i in range(len(A)):\n", | ||
| 42 | " for j in range(len(A)):\n", | ||
| 43 | " for k in range(len(A)):\n", | ||
| 44 | " S[i][j] = S[i][j] + A[i][k] * B[k][j]\n", | ||
| 45 | " return S\n", | ||
| 46 | "\n", | ||
| 47 | "N = 200\n", | ||
| 48 | "A = [ [randint(0,100) for i in range(N)] for j in range(N) ]\n", | ||
| 49 | "B = [ [randint(0,100) for i in range(N)] for j in range(N) ]\n", | ||
| 50 | "\n", | ||
| 51 | "t0 = time.process_time()\n", | ||
| 52 | "add(A,B)\n", | ||
| 53 | "t1 = time.process_time()\n", | ||
| 54 | "prod(A,B)\n", | ||
| 55 | "t2 = time.process_time()\n", | ||
| 56 | "\n", | ||
| 57 | "print(\"Time for add: \", t1-t0)\n", | ||
| 58 | "print(\"Time for prod:\", t2-t1)" | ||
| 59 | ] | ||
| 60 | }, | ||
| 61 | { | ||
| 62 | "cell_type": "markdown", | ||
| 63 | "metadata": {}, | ||
| 64 | "source": [ | ||
| 65 | "# Sorting a list, slow version\n", | ||
| 66 | "\n", | ||
| 67 | "The following code implements a slow version of the so-called *insertion sort* alogithm\n", | ||
| 68 | "\n", | ||
| 69 | "Complexity: $O(n^2)$." | ||
| 70 | ] | ||
| 71 | }, | ||
| 72 | { | ||
| 73 | "cell_type": "code", | ||
| 74 | "execution_count": 1, | ||
| 75 | "metadata": {}, | ||
| 76 | "outputs": [ | ||
| 77 | { | ||
| 78 | "name": "stdout", | ||
| 79 | "output_type": "stream", | ||
| 80 | "text": [ | ||
| 81 | "Running time: 1.1191449070000001\n" | ||
| 82 | ] | ||
| 83 | } | ||
| 84 | ], | ||
| 85 | "source": [ | ||
| 86 | "from random import randint\n", | ||
| 87 | "import time\n", | ||
| 88 | "\n", | ||
| 89 | "def correct_position(e, S):\n", | ||
| 90 | " for i in range(len(S)):\n", | ||
| 91 | " if S[i] > e:\n", | ||
| 92 | " return i\n", | ||
| 93 | " return len(S)\n", | ||
| 94 | "\n", | ||
| 95 | "def sort_list(L):\n", | ||
| 96 | " S = []\n", | ||
| 97 | " for e in L:\n", | ||
| 98 | " cp = correct_position(e, S)\n", | ||
| 99 | " S.insert(cp, e)\n", | ||
| 100 | " return S\n", | ||
| 101 | "\n", | ||
| 102 | "N = 10000\n", | ||
| 103 | "L = [randint(0,10**9) for i in range(N)]\n", | ||
| 104 | "\n", | ||
| 105 | "t0 = time.process_time()\n", | ||
| 106 | "sort_list(L)\n", | ||
| 107 | "t1 = time.process_time()\n", | ||
| 108 | "\n", | ||
| 109 | "print(\"Running time:\", t1-t0)" | ||
| 110 | ] | ||
| 111 | }, | ||
| 112 | { | ||
| 113 | "cell_type": "markdown", | ||
| 114 | "metadata": {}, | ||
| 115 | "source": [ | ||
| 116 | "# Binary search\n", | ||
| 117 | "\n", | ||
| 118 | "The following code implements a binary search.\n", | ||
| 119 | "\n", | ||
| 120 | "Complexity: $O(\\log_2(n))$" | ||
| 121 | ] | ||
| 122 | }, | ||
| 123 | { | ||
| 124 | "cell_type": "code", | ||
| 125 | "execution_count": 3, | ||
| 126 | "metadata": {}, | ||
| 127 | "outputs": [ | ||
| 128 | { | ||
| 129 | "name": "stdout", | ||
| 130 | "output_type": "stream", | ||
| 131 | "text": [ | ||
| 132 | "The correct position of e = 216197744 in L is:\n", | ||
| 133 | "... 216196218 216197540 e 216198673 216198962 ...\n", | ||
| 134 | "\n", | ||
| 135 | "Time for sorting: 0.26413054400000036\n", | ||
| 136 | "Time for searching: 9.616099999965044e-05\n" | ||
| 137 | ] | ||
| 138 | } | ||
| 139 | ], | ||
| 140 | "source": [ | ||
| 141 | "from random import randint\n", | ||
| 142 | "import time\n", | ||
| 143 | "\n", | ||
| 144 | "def binary_search(e, S, start, end):\n", | ||
| 145 | " if start == end:\n", | ||
| 146 | " return start\n", | ||
| 147 | " midpoint = (start+end) // 2\n", | ||
| 148 | " if e < S[midpoint]:\n", | ||
| 149 | " return binary_search(e, S, start, midpoint)\n", | ||
| 150 | " else:\n", | ||
| 151 | " return binary_search(e, S, midpoint+1, end)\n", | ||
| 152 | " \n", | ||
| 153 | "N = 1000000\n", | ||
| 154 | "L = [randint(0,10**9) for i in range(N)]\n", | ||
| 155 | "e = randint(0,10**9)\n", | ||
| 156 | "\n", | ||
| 157 | "t0 = time.process_time()\n", | ||
| 158 | "L.sort() # Using Python's sort()\n", | ||
| 159 | "t1 = time.process_time()\n", | ||
| 160 | "i = binary_search(e, L, 0, len(L))\n", | ||
| 161 | "t2 = time.process_time()\n", | ||
| 162 | "print(\"The correct position of e =\", e, \"in L is:\")\n", | ||
| 163 | "print(\"...\", L[i-2], L[i-1], \"e\", L[i], L[i+1], \"...\")\n", | ||
| 164 | "print(\"\")\n", | ||
| 165 | "print(\"Time for sorting: \", t1-t0)\n", | ||
| 166 | "print(\"Time for searching:\", t2-t1)\n" | ||
| 167 | ] | ||
| 168 | }, | ||
| 169 | { | ||
| 170 | "cell_type": "markdown", | ||
| 171 | "metadata": {}, | ||
| 172 | "source": [ | ||
| 173 | "# Sorting a list, fast version (with binary_search)\n", | ||
| 174 | "\n", | ||
| 175 | "The following code uses the function `binary_search()` above instead of `correct_position()` in our insertion sort algorithm.\n", | ||
| 176 | "\n", | ||
| 177 | "Complexity: $O(n\\log_2(n))$" | ||
| 178 | ] | ||
| 179 | }, | ||
| 180 | { | ||
| 181 | "cell_type": "code", | ||
| 182 | "execution_count": 69, | ||
| 183 | "metadata": {}, | ||
| 184 | "outputs": [ | ||
| 185 | { | ||
| 186 | "name": "stdout", | ||
| 187 | "output_type": "stream", | ||
| 188 | "text": [ | ||
| 189 | "Running time: 0.03710268399998995\n" | ||
| 190 | ] | ||
| 191 | } | ||
| 192 | ], | ||
| 193 | "source": [ | ||
| 194 | "from random import randint\n", | ||
| 195 | "import time\n", | ||
| 196 | "\n", | ||
| 197 | "def binary_search(e, S, start, end):\n", | ||
| 198 | " if start == end:\n", | ||
| 199 | " return start\n", | ||
| 200 | " midpoint = (start+end) // 2\n", | ||
| 201 | " if e < S[midpoint]:\n", | ||
| 202 | " return binary_search(e, S, start, midpoint)\n", | ||
| 203 | " else:\n", | ||
| 204 | " return binary_search(e, S, midpoint+1, end)\n", | ||
| 205 | " \n", | ||
| 206 | "def sort_list(L):\n", | ||
| 207 | " S = []\n", | ||
| 208 | " for e in L:\n", | ||
| 209 | " cp = binary_search(e, S, 0, len(S)) # Changed here\n", | ||
| 210 | " S.insert(cp, e)\n", | ||
| 211 | " return S\n", | ||
| 212 | " \n", | ||
| 213 | "N = 10000\n", | ||
| 214 | "L = [randint(0,10**9) for i in range(N)]\n", | ||
| 215 | "\n", | ||
| 216 | "t0 = time.process_time()\n", | ||
| 217 | "sort_list(L)\n", | ||
| 218 | "t1 = time.process_time()\n", | ||
| 219 | "\n", | ||
| 220 | "print(\"Running time:\", t1-t0)" | ||
| 221 | ] | ||
| 222 | }, | ||
| 223 | { | ||
| 224 | "cell_type": "markdown", | ||
| 225 | "metadata": {}, | ||
| 226 | "source": [ | ||
| 227 | "# Fast exponentiation\n", | ||
| 228 | "\n", | ||
| 229 | "The following cell contains two functions for computing $a^n$ ($n$ non-negative integer): a slow one that runs in $O(n)$ and a fast one that runs in $O(\\log_2(n))$. We compare these two also with Python's built-in operator `**`.\n", | ||
| 230 | "\n", | ||
| 231 | "Complexity: $O(n)$ for the slow algorithm, $O(\\log_2(n))$ for the other two." | ||
| 232 | ] | ||
| 233 | }, | ||
| 234 | { | ||
| 235 | "cell_type": "code", | ||
| 236 | "execution_count": 30, | ||
| 237 | "metadata": {}, | ||
| 238 | "outputs": [ | ||
| 239 | { | ||
| 240 | "name": "stdout", | ||
| 241 | "output_type": "stream", | ||
| 242 | "text": [ | ||
| 243 | "2.71828179834636\n", | ||
| 244 | "2.7182817863957984\n", | ||
| 245 | "2.7182817983473577\n", | ||
| 246 | "Time for slow_power(): 3.234879998000004\n", | ||
| 247 | "Time for fast_power(): 9.059099999575437e-05\n", | ||
| 248 | "Time for Python's **: 0.00010159500000384014\n" | ||
| 249 | ] | ||
| 250 | } | ||
| 251 | ], | ||
| 252 | "source": [ | ||
| 253 | "import time\n", | ||
| 254 | "\n", | ||
| 255 | "def slow_power(a, n):\n", | ||
| 256 | " r = 1\n", | ||
| 257 | " for i in range(n):\n", | ||
| 258 | " r = r * a\n", | ||
| 259 | " return r\n", | ||
| 260 | "\n", | ||
| 261 | "def fast_power(a, n):\n", | ||
| 262 | " if n == 0:\n", | ||
| 263 | " return 1\n", | ||
| 264 | " if n%2 == 0:\n", | ||
| 265 | " return fast_power(a*a, n//2)\n", | ||
| 266 | " else:\n", | ||
| 267 | " return a * fast_power(a, n-1)\n", | ||
| 268 | "\n", | ||
| 269 | "a = 1.00000001\n", | ||
| 270 | "n = 100000000\n", | ||
| 271 | "\n", | ||
| 272 | "t0 = time.process_time()\n", | ||
| 273 | "print(slow_power(a, n))\n", | ||
| 274 | "t1 = time.process_time()\n", | ||
| 275 | "print(fast_power(a, n))\n", | ||
| 276 | "t2 = time.process_time()\n", | ||
| 277 | "print(a**n)\n", | ||
| 278 | "t3 = time.process_time()\n", | ||
| 279 | "\n", | ||
| 280 | "print(\"Time for slow_power():\", t1-t0)\n", | ||
| 281 | "print(\"Time for fast_power():\", t2-t1)\n", | ||
| 282 | "print(\"Time for Python's **: \", t3-t2)" | ||
| 283 | ] | ||
| 284 | }, | ||
| 285 | { | ||
| 286 | "cell_type": "markdown", | ||
| 287 | "metadata": {}, | ||
| 288 | "source": [ | ||
| 289 | "# Fast gcd\n", | ||
| 290 | "\n", | ||
| 291 | "Complexity: $O(\\log_2(n))$" | ||
| 292 | ] | ||
| 293 | }, | ||
| 294 | { | ||
| 295 | "cell_type": "code", | ||
| 296 | "execution_count": 31, | ||
| 297 | "metadata": {}, | ||
| 298 | "outputs": [ | ||
| 299 | { | ||
| 300 | "name": "stdout", | ||
| 301 | "output_type": "stream", | ||
| 302 | "text": [ | ||
| 303 | "126\n", | ||
| 304 | "Running time: 0.00017707599999994272\n" | ||
| 305 | ] | ||
| 306 | } | ||
| 307 | ], | ||
| 308 | "source": [ | ||
| 309 | "import time\n", | ||
| 310 | "\n", | ||
| 311 | "def gcd(a, b):\n", | ||
| 312 | " if b == 0:\n", | ||
| 313 | " return a\n", | ||
| 314 | " else:\n", | ||
| 315 | " return gcd(b, a%b)\n", | ||
| 316 | "\n", | ||
| 317 | "t0 = time.process_time()\n", | ||
| 318 | "print(gcd(155275387236018, 572335397352432))\n", | ||
| 319 | "t1 = time.process_time()\n", | ||
| 320 | "\n", | ||
| 321 | "print(\"Running time:\", t1-t0)" | ||
| 322 | ] | ||
| 323 | }, | ||
| 324 | { | ||
| 325 | "cell_type": "markdown", | ||
| 326 | "metadata": {}, | ||
| 327 | "source": [ | ||
| 328 | "# Fibonacci numbers\n", | ||
| 329 | "\n", | ||
| 330 | "In the following cell there are two functions that compute the $n$-th Fibonacci number. They are almost the same, but the second one memorizes the results in a list to avoid computing them multiple times, and it is much much faster.\n", | ||
| 331 | "\n", | ||
| 332 | "Complexity: $O\\left(\\left(\\frac{1+\\sqrt 5}{2}\\right)^n\\right)\\sim O(1.6^n)$ for the slow version, $O(n)$ for the fast version." | ||
| 333 | ] | ||
| 334 | }, | ||
| 335 | { | ||
| 336 | "cell_type": "code", | ||
| 337 | "execution_count": 37, | ||
| 338 | "metadata": {}, | ||
| 339 | "outputs": [ | ||
| 340 | { | ||
| 341 | "name": "stdout", | ||
| 342 | "output_type": "stream", | ||
| 343 | "text": [ | ||
| 344 | "9227465\n", | ||
| 345 | "9227465\n", | ||
| 346 | "Time for F_slow: 2.3301570169999906\n", | ||
| 347 | "Time for F_fast: 8.848800000293977e-05\n" | ||
| 348 | ] | ||
| 349 | } | ||
| 350 | ], | ||
| 351 | "source": [ | ||
| 352 | "import time\n", | ||
| 353 | "\n", | ||
| 354 | "F_memorized = [-1] * (10**6)\n", | ||
| 355 | "\n", | ||
| 356 | "def F_slow(n):\n", | ||
| 357 | " if n <= 1:\n", | ||
| 358 | " return n\n", | ||
| 359 | " else:\n", | ||
| 360 | " return F_slow(n-1) + F_slow(n-2)\n", | ||
| 361 | " \n", | ||
| 362 | "def F_fast(n):\n", | ||
| 363 | " if F_memorized[n] == -1:\n", | ||
| 364 | " if n <= 1:\n", | ||
| 365 | " F_memorized[n] = n\n", | ||
| 366 | " else:\n", | ||
| 367 | " F_memorized[n] = F_fast(n-1) + F_fast(n-2)\n", | ||
| 368 | " \n", | ||
| 369 | " return F_memorized[n]\n", | ||
| 370 | "\n", | ||
| 371 | "n = 35\n", | ||
| 372 | "\n", | ||
| 373 | "t0 = time.process_time()\n", | ||
| 374 | "print(F_slow(n))\n", | ||
| 375 | "t1 = time.process_time()\n", | ||
| 376 | "print(F_fast(n))\n", | ||
| 377 | "t2 = time.process_time()\n", | ||
| 378 | "\n", | ||
| 379 | "print(\"Time for F_slow:\", t1-t0)\n", | ||
| 380 | "print(\"Time for F_fast:\", t2-t1)" | ||
| 381 | ] | ||
| 382 | }, | ||
| 383 | { | ||
| 384 | "cell_type": "code", | ||
| 385 | "execution_count": null, | ||
| 386 | "metadata": {}, | ||
| 387 | "outputs": [], | ||
| 388 | "source": [] | ||
| 389 | } | ||
| 390 | ], | ||
| 391 | "metadata": { | ||
| 392 | "kernelspec": { | ||
| 393 | "display_name": "Python 3", | ||
| 394 | "language": "python", | ||
| 395 | "name": "python3" | ||
| 396 | }, | ||
| 397 | "language_info": { | ||
| 398 | "codemirror_mode": { | ||
| 399 | "name": "ipython", | ||
| 400 | "version": 3 | ||
| 401 | }, | ||
| 402 | "file_extension": ".py", | ||
| 403 | "mimetype": "text/x-python", | ||
| 404 | "name": "python", | ||
| 405 | "nbconvert_exporter": "python", | ||
| 406 | "pygments_lexer": "ipython3", | ||
| 407 | "version": "3.8.5" | ||
| 408 | } | ||
| 409 | }, | ||
| 410 | "nbformat": 4, | ||
| 411 | "nbformat_minor": 4 | ||
| 412 | } | ||
