mathsoftware

A course about LaTeX and SageMath
git clone https://git.tronto.net/mathsoftware
Download | Log | Files | Refs | README | LICENSE

X1-ComputationalComplexity-checkpoint.ipynb (10122B)


      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": 37,
     17    "metadata": {},
     18    "outputs": [
     19     {
     20      "name": "stdout",
     21      "output_type": "stream",
     22      "text": [
     23       "Time for add:  0.00012074300000008975\n",
     24       "Time for prod: 0.00036587199999971176\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 = 10\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": 61,
     75    "metadata": {},
     76    "outputs": [
     77     {
     78      "name": "stdout",
     79      "output_type": "stream",
     80      "text": [
     81       "Running time: 1.1012288430000012\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": 53,
    126    "metadata": {},
    127    "outputs": [
    128     {
    129      "name": "stdout",
    130      "output_type": "stream",
    131      "text": [
    132       "The correct position of e = 658230309 in L is:\n",
    133       "... 658211821 658224379 e 658234625 658246765 ...\n",
    134       "\n",
    135       "Time for sorting:   0.021211020999999164\n",
    136       "Time for searching: 7.820199999741817e-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 = 100000\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": null,
    338    "metadata": {},
    339    "outputs": [],
    340    "source": [
    341     "import time\n",
    342     "\n",
    343     "F_memorized = [-1] * (10**6)\n",
    344     "\n",
    345     "def F_slow(n):\n",
    346     "    if n <= 1:\n",
    347     "        return n\n",
    348     "    else:\n",
    349     "        return F_slow(n-1) + F_slow(n-2)\n",
    350     "    \n",
    351     "def F_fast(n):\n",
    352     "    if F_memorized[n] == -1:\n",
    353     "        if n <= 1:\n",
    354     "            F_memorized[n] = n\n",
    355     "        else:\n",
    356     "            F_memorized[n] = F_fast(n-1) + F_fast(n-2)\n",
    357     "    \n",
    358     "    return F_memorized[n]\n",
    359     "\n",
    360     "n = 40\n",
    361     "\n",
    362     "t0 = time.process_time()\n",
    363     "print(F_slow(n))\n",
    364     "t1 = time.process_time()\n",
    365     "print(F_fast(n))\n",
    366     "t2 = time.process_time()\n",
    367     "\n",
    368     "print(\"Time for F_slow:\", t1-t0)\n",
    369     "print(\"Time for F_fast:\", t2-t1)"
    370    ]
    371   }
    372  ],
    373  "metadata": {
    374   "kernelspec": {
    375    "display_name": "Python 3",
    376    "language": "python",
    377    "name": "python3"
    378   },
    379   "language_info": {
    380    "codemirror_mode": {
    381     "name": "ipython",
    382     "version": 3
    383    },
    384    "file_extension": ".py",
    385    "mimetype": "text/x-python",
    386    "name": "python",
    387    "nbconvert_exporter": "python",
    388    "pygments_lexer": "ipython3",
    389    "version": "3.8.5"
    390   }
    391  },
    392  "nbformat": 4,
    393  "nbformat_minor": 4
    394 }