aboutsummaryrefslogtreecommitdiff
path: root/src/Lecture7/notebook/X1-ComputationalComplexity-notebook.ipynb
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/Lecture7/notebook/X1-ComputationalComplexity-notebook.ipynb412
1 files changed, 412 insertions, 0 deletions
diff --git a/src/Lecture7/notebook/X1-ComputationalComplexity-notebook.ipynb b/src/Lecture7/notebook/X1-ComputationalComplexity-notebook.ipynb
new file mode 100644
index 0000000..18be171
--- /dev/null
+++ b/src/Lecture7/notebook/X1-ComputationalComplexity-notebook.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": 3,
17 "metadata": {},
18 "outputs": [
19 {
20 "name": "stdout",
21 "output_type": "stream",
22 "text": [
23 "Time for add: 0.01961983600000039\n",
24 "Time for prod: 11.278560734\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 = 400\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": 7,
75 "metadata": {},
76 "outputs": [
77 {
78 "name": "stdout",
79 "output_type": "stream",
80 "text": [
81 "Running time: 1.2679741750000009\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 "#L.sort()\n",
108 "t1 = time.process_time()\n",
109 "\n",
110 "print(\"Running time:\", t1-t0)"
111 ]
112 },
113 {
114 "cell_type": "markdown",
115 "metadata": {},
116 "source": [
117 "# Binary search\n",
118 "\n",
119 "The following code implements a binary search.\n",
120 "\n",
121 "Complexity: $O(\\log_2(n))$"
122 ]
123 },
124 {
125 "cell_type": "code",
126 "execution_count": 8,
127 "metadata": {},
128 "outputs": [
129 {
130 "name": "stdout",
131 "output_type": "stream",
132 "text": [
133 "The correct position of e = 36132116 in L is:\n",
134 "... 36130178 36131096 e 36132160 36132386 ...\n",
135 "\n",
136 "Time for sorting: 0.4964379069999971\n",
137 "Time for searching: 0.00012017000000241751\n"
138 ]
139 }
140 ],
141 "source": [
142 "from random import randint\n",
143 "import time\n",
144 "\n",
145 "def binary_search(e, S, start, end):\n",
146 " if start == end:\n",
147 " return start\n",
148 " midpoint = (start+end) // 2\n",
149 " if e < S[midpoint]:\n",
150 " return binary_search(e, S, start, midpoint)\n",
151 " else:\n",
152 " return binary_search(e, S, midpoint+1, end)\n",
153 " \n",
154 "N = 1000000\n",
155 "L = [randint(0,10**9) for i in range(N)]\n",
156 "e = randint(0,10**9)\n",
157 "\n",
158 "t0 = time.process_time()\n",
159 "L.sort() # Using Python's sort()\n",
160 "t1 = time.process_time()\n",
161 "i = binary_search(e, L, 0, len(L))\n",
162 "t2 = time.process_time()\n",
163 "print(\"The correct position of e =\", e, \"in L is:\")\n",
164 "print(\"...\", L[i-2], L[i-1], \"e\", L[i], L[i+1], \"...\")\n",
165 "print(\"\")\n",
166 "print(\"Time for sorting: \", t1-t0)\n",
167 "print(\"Time for searching:\", t2-t1)\n"
168 ]
169 },
170 {
171 "cell_type": "markdown",
172 "metadata": {},
173 "source": [
174 "# Sorting a list, fast version (with binary_search)\n",
175 "\n",
176 "The following code uses the function `binary_search()` above instead of `correct_position()` in our insertion sort algorithm.\n",
177 "\n",
178 "Complexity: $O(n\\log_2(n))$"
179 ]
180 },
181 {
182 "cell_type": "code",
183 "execution_count": 11,
184 "metadata": {},
185 "outputs": [
186 {
187 "name": "stdout",
188 "output_type": "stream",
189 "text": [
190 "Running time: 1.5683504970000008\n"
191 ]
192 }
193 ],
194 "source": [
195 "from random import randint\n",
196 "import time\n",
197 "\n",
198 "def binary_search(e, S, start, end):\n",
199 " if start == end:\n",
200 " return start\n",
201 " midpoint = (start+end) // 2\n",
202 " if e < S[midpoint]:\n",
203 " return binary_search(e, S, start, midpoint)\n",
204 " else:\n",
205 " return binary_search(e, S, midpoint+1, end)\n",
206 " \n",
207 "def sort_list(L):\n",
208 " S = []\n",
209 " for e in L:\n",
210 " cp = binary_search(e, S, 0, len(S)) # Changed here\n",
211 " S.insert(cp, e)\n",
212 " return S\n",
213 " \n",
214 "N = 100000\n",
215 "L = [randint(0,10**9) for i in range(N)]\n",
216 "\n",
217 "t0 = time.process_time()\n",
218 "sort_list(L)\n",
219 "t1 = time.process_time()\n",
220 "\n",
221 "print(\"Running time:\", t1-t0)"
222 ]
223 },
224 {
225 "cell_type": "markdown",
226 "metadata": {},
227 "source": [
228 "# Fast exponentiation\n",
229 "\n",
230 "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",
231 "\n",
232 "Complexity: $O(n)$ for the slow algorithm, $O(\\log_2(n))$ for the other two."
233 ]
234 },
235 {
236 "cell_type": "code",
237 "execution_count": 14,
238 "metadata": {},
239 "outputs": [
240 {
241 "name": "stdout",
242 "output_type": "stream",
243 "text": [
244 "2.71828179834636\n",
245 "2.7182817863957984\n",
246 "2.7182817983473577\n",
247 "Time for slow_power(): 3.5567659670000005\n",
248 "Time for fast_power(): 0.00014241699999928414\n",
249 "Time for Python's **: 9.477100000054861e-05\n"
250 ]
251 }
252 ],
253 "source": [
254 "import time\n",
255 "\n",
256 "def slow_power(a, n):\n",
257 " r = 1\n",
258 " for i in range(n):\n",
259 " r = r * a\n",
260 " return r\n",
261 "\n",
262 "def fast_power(a, n):\n",
263 " if n == 0:\n",
264 " return 1\n",
265 " if n%2 == 0:\n",
266 " return fast_power(a*a, n//2)\n",
267 " else:\n",
268 " return a * fast_power(a, n-1)\n",
269 "\n",
270 "a = 1.00000001\n",
271 "n = 100000000\n",
272 "\n",
273 "t0 = time.process_time()\n",
274 "print(slow_power(a, n))\n",
275 "t1 = time.process_time()\n",
276 "print(fast_power(a, n))\n",
277 "t2 = time.process_time()\n",
278 "print(a**n)\n",
279 "t3 = time.process_time()\n",
280 "\n",
281 "print(\"Time for slow_power():\", t1-t0)\n",
282 "print(\"Time for fast_power():\", t2-t1)\n",
283 "print(\"Time for Python's **: \", t3-t2)"
284 ]
285 },
286 {
287 "cell_type": "markdown",
288 "metadata": {},
289 "source": [
290 "# Fast gcd\n",
291 "\n",
292 "Complexity: $O(\\log_2(n))$"
293 ]
294 },
295 {
296 "cell_type": "code",
297 "execution_count": 15,
298 "metadata": {},
299 "outputs": [
300 {
301 "name": "stdout",
302 "output_type": "stream",
303 "text": [
304 "126\n",
305 "Running time: 0.0002987290000007192\n"
306 ]
307 }
308 ],
309 "source": [
310 "import time\n",
311 "\n",
312 "def gcd(a, b):\n",
313 " if b == 0:\n",
314 " return a\n",
315 " else:\n",
316 " return gcd(b, a%b)\n",
317 "\n",
318 "t0 = time.process_time()\n",
319 "print(gcd(155275387236018, 572335397352432))\n",
320 "t1 = time.process_time()\n",
321 "\n",
322 "print(\"Running time:\", t1-t0)"
323 ]
324 },
325 {
326 "cell_type": "markdown",
327 "metadata": {},
328 "source": [
329 "# Fibonacci numbers\n",
330 "\n",
331 "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",
332 "\n",
333 "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."
334 ]
335 },
336 {
337 "cell_type": "code",
338 "execution_count": 24,
339 "metadata": {},
340 "outputs": [
341 {
342 "name": "stdout",
343 "output_type": "stream",
344 "text": [
345 "222232244629420445529739893461909967206666939096499764990979600\n",
346 "Time for F_slow: 3.0404000000316955e-05\n",
347 "Time for F_fast: 0.0003859389999973928\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 = 300\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}

Generated with cgit - Back to sebastiano.tronto.net