{ "cells": [ { "cell_type": "markdown", "id": "b93130a6-e49f-4aec-9b11-13ef64cb5c5c", "metadata": {}, "source": [ "This notebook requires cython to be installed properly and that certain files are present in the current folder." ] }, { "cell_type": "markdown", "id": "ec77f5ad-bf26-4f59-94f2-2e593eac8a9c", "metadata": {}, "source": [ "# 1. Hello Cython!" ] }, { "cell_type": "markdown", "id": "e2ccb884-1c85-4448-9f1c-1f1ea094ca5f", "metadata": {}, "source": [ "For the commands in this section of the notebook to run well, the script `hello_setup.py` must be present in the current folder." ] }, { "cell_type": "code", "execution_count": 1, "id": "8982a0d7-21ef-4dd7-9d22-d0af6dcd3c91", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['game_of_life.py',\n", " 'hello_setup.py',\n", " 'integral4pi.py',\n", " 'integral4pi_cdeffun_apply.py',\n", " 'integral4pi_cdeffun_setup.py',\n", " 'integral4pi_extcfun_apply.py',\n", " 'integral4pi_extcfun_setup.py',\n", " 'integral4pi_typed_apply.py',\n", " 'integral4pi_typed_setup.py',\n", " 'run_game_better_apply.py',\n", " 'run_game_better_setup.py',\n", " 'run_game_better_show.py',\n", " 'run_game_of_life.py']" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import os\n", "L = os.listdir('.')\n", "[x for x in L if x[-2:] == 'py']" ] }, { "cell_type": "markdown", "id": "6e4d5251-afcd-4401-b77b-6c6f88fd1bbf", "metadata": {}, "source": [ "The `os` module allows an operating system independent listing of the files in the current folder." ] }, { "cell_type": "markdown", "id": "16906f25-784a-4627-afb5-e508ded44d19", "metadata": {}, "source": [ "Cython code has the extension `.pyx`. The directory listing `L` must contain the file `hello.pyx`." ] }, { "cell_type": "code", "execution_count": 2, "id": "a1c29632-0921-4b2a-881e-4ec0aed7f02a", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "'hello.pyx' in L" ] }, { "cell_type": "markdown", "id": "24c54d55-b4a0-4a75-a270-39ea6f92bafc", "metadata": {}, "source": [ "Let us see what the content of `hello.pyx` is:" ] }, { "cell_type": "code", "execution_count": 3, "id": "0162c3f0-48dc-4a27-872a-3a1cbafb87b8", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "# cython: language_level=3\n", "\n", "# L-15 MCS 507 Mon 25 Sep 2023 : hello.pyx\n", "\n", "\"\"\"\n", "This file is needed for our first \"hello world\" with Cython,\n", "see the file hello_setup.py to build the shared object file.\n", "\"\"\"\n", "\n", "def say_hello(name):\n", " \"\"\"\n", " Prints hello followed by the name.\n", " \"\"\"\n", " print(\"hello\", name)\n" ] } ], "source": [ "with open('hello.pyx') as f:\n", " for line in f.readlines():\n", " print(line[:-1])" ] }, { "cell_type": "markdown", "id": "e87885f2-5bb6-4a79-9a8c-6bd990b93191", "metadata": {}, "source": [ "The `hello_setup.py` defines an extension module `hello` which exports the function `say_hello()`." ] }, { "cell_type": "code", "execution_count": 4, "id": "ab1ee631-023a-44e7-bbc1-c32529c4a375", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "# L-15 MCS 507 Mon 25 Sep 2023 : hello_setup.py\n", "\n", "\"\"\"\n", "We build the extension module defined by hello.py with cython via\n", "python3 hello_setup.py build_ext --inplace\n", "\"\"\"\n", "\n", "from distutils.core import setup\n", "from distutils.extension import Extension\n", "from Cython.Distutils import build_ext\n", "\n", "EXT_MODULES = [Extension(\"hello\", [\"hello.pyx\"])]\n", "\n", "setup(\n", " name = 'hello world' ,\n", " cmdclass = {'build_ext': build_ext},\n", " ext_modules = EXT_MODULES\n", ")\n" ] } ], "source": [ "with open('hello_setup.py') as f:\n", " for line in f.readlines():\n", " print(line[:-1])" ] }, { "cell_type": "markdown", "id": "a55562c5-c807-4f26-af5e-4522071efb65", "metadata": {}, "source": [ "Now we execute the command to compile the code, from within a code cell, observe the `!` in front of the command." ] }, { "cell_type": "code", "execution_count": 5, "id": "0e6dd8b4-befa-40f3-bb04-251f900ae2d7", "metadata": {}, "outputs": [], "source": [ "!python hello_setup.py build_ext --inplace" ] }, { "cell_type": "code", "execution_count": 6, "id": "fc84b98d-f350-4f38-b79b-6e98dcc2bfcf", "metadata": {}, "outputs": [], "source": [ "from hello import say_hello" ] }, { "cell_type": "code", "execution_count": 7, "id": "cee123e0-65be-4a4b-b725-d45105744ebb", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "hello me\n" ] } ], "source": [ "say_hello('me')" ] }, { "cell_type": "markdown", "id": "a7eab286-51c0-4fc0-a6fe-44e33669476f", "metadata": {}, "source": [ "# 2. Numerical Integration" ] }, { "cell_type": "markdown", "id": "f1a3f70b-ab65-41b3-b0b8-2af1850e8a99", "metadata": {}, "source": [ "For a computational intensive, yet simple computation, consider\n", "\n", "$$\n", " \\frac{\\pi}{4} = \\int_0^1 \\sqrt{1-x^2} ~\\! dx\n", "$$\n", "\n", "approximated with the composite Trapezoidal rule:\n", "\n", "$$\n", " \\int_0^1 \\sqrt{1-x^2} ~\\! dx\n", " \\approx \\frac{1}{n} \n", " \\left( \\frac{1}{2} \n", " + \\sum_{i=1}^{n-1} \\sqrt{1 - \\left(\\frac{i}{n} \\right)^2}\n", " \\right).\n", "$$\n", "\n", "We let $n = 10^8$ and make 100,000,000 square root function calls." ] }, { "cell_type": "markdown", "id": "41781a35-ab63-46a3-8c7c-7ce190fff74b", "metadata": {}, "source": [ "## 2.1 a pure Python definition" ] }, { "cell_type": "code", "execution_count": 8, "id": "59c2d15d-c0f5-4253-b66b-1d5826d1aa2d", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "# L-15 MCS 507 Mon 25 Sep 2023 : integral4pi.py\n", "\n", "\"\"\"\n", "This script applies the composite trapezoidal rule\n", "to the integral of sqrt(1-x^2) for x from 0 to 1,\n", "to obtain an approximation for pi.\n", "This inefficient computational expensive method\n", "gives us an example to optimize with cython.\n", "\"\"\"\n", "\n", "from math import sqrt # do not import in circle !!!\n", "\n", "def circle(xvl):\n", " \"\"\"\n", " Returns the y corresponding to xvl\n", " on the upper half of the unit circle.\n", " \"\"\"\n", " return sqrt(1-xvl**2)\n", "\n", "def integral4pi(nbvals):\n", " \"\"\"\n", " Approximates Pi with the trapezoidal\n", " rule with nbvals subintervals of [0,1].\n", " \"\"\"\n", " step = 1.0/nbvals\n", " result = (circle(0)+circle(1))/2\n", " for i in range(nbvals):\n", " result += circle(i*step)\n", " return 4*result*step\n", "\n", "def main():\n", " \"\"\"\n", " Does the timing of integral4pi.\n", " \"\"\"\n", " from time import perf_counter\n", " start_time = perf_counter()\n", " approx = integral4pi(10**8)\n", " stop_time = perf_counter()\n", " print('pi =', approx)\n", " elapsed = stop_time - start_time\n", " print('elapsed time = %.3f seconds' % elapsed)\n", "\n", "main()\n" ] } ], "source": [ "with open('integral4pi.py') as f:\n", " for line in f.readlines():\n", " print(line[:-1])" ] }, { "cell_type": "code", "execution_count": 9, "id": "f05c7bb3-5150-4ab4-9757-cd7bce7cf0e2", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "pi = 3.141592693586875\n", "elapsed time = 19.272 seconds\n" ] } ], "source": [ "!python integral4pi.py" ] }, { "cell_type": "markdown", "id": "c371d89c-b64b-4fe5-a688-f0bcdb541045", "metadata": {}, "source": [ "## 2.2 adding type declarations" ] }, { "cell_type": "code", "execution_count": 10, "id": "a3e81cca-dc98-4f19-bfcf-01da70faccc2", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "# cython: language_level=3\n", "\n", "# L-15 MCS 507 Mon 25 Sep 2023 : integral4pi_typed.pyx\n", "\n", "\"\"\"\n", "This script applies the composite trapezoidal rule\n", "to the integral of sqrt(1-x^2) for x from 0 to 1,\n", "to obtain an approximation for Pi.\n", "Type declarations have been added so the for loop\n", "will be compiled into pure C code.\n", "\"\"\"\n", "\n", "from math import sqrt\n", "\n", "def circle(double xvl):\n", " \"\"\"\n", " Returns the y corresponding to xvl\n", " on the upper half of the unit circle.\n", " \"\"\"\n", " return sqrt(1-xvl**2)\n", "\n", "def integral4pi(int nbvals):\n", " \"\"\"\n", " Approximates Pi with the trapezoidal\n", " rule with nbvals subintervals of [0,1].\n", " \"\"\"\n", " cdef int i\n", " cdef double step, result\n", " step = 1.0/nbvals\n", " result = (circle(0)+circle(1))/2\n", " for i in range(nbvals):\n", " result += circle(i*step)\n", " return 4*result*step\n" ] } ], "source": [ "with open('integral4pi_typed.pyx') as f:\n", " for line in f.readlines():\n", " print(line[:-1])" ] }, { "cell_type": "markdown", "id": "778a23aa-bcf8-4993-8e6a-f8a608f885dd", "metadata": {}, "source": [ "To execute the code defined in the `pyx` file, we must compile it." ] }, { "cell_type": "code", "execution_count": 11, "id": "67807324-1e75-45be-a632-c12586464986", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "# L-15 MCS 507 Mon 25 Sep 2023 : integral4pi_typed_setup.py\n", "\n", "\"\"\"\n", "We build the extension module integral4pi_typed with cython via\n", "python integral4pi_typed_setup.py build_ext --inplace\n", "\"\"\"\n", "\n", "from distutils.core import setup\n", "from distutils.extension import Extension\n", "from Cython.Distutils import build_ext\n", "\n", "EXT_MODULES = [Extension(\"integral4pi_typed\",\n", " [\"integral4pi_typed.pyx\"])]\n", "\n", "setup(\n", " name = 'integral approximation for pi' ,\n", " cmdclass = {'build_ext': build_ext},\n", " ext_modules = EXT_MODULES\n", ")\n" ] } ], "source": [ "with open('integral4pi_typed_setup.py') as f:\n", " for line in f.readlines():\n", " print(line[:-1])" ] }, { "cell_type": "markdown", "id": "a8602713-4de1-4a4a-8297-90c24969a6a4", "metadata": {}, "source": [ "We build the extension module as follows" ] }, { "cell_type": "code", "execution_count": 12, "id": "6ef3e44c-27d0-4c9a-8374-840df46624c6", "metadata": {}, "outputs": [], "source": [ "!python integral4pi_typed_setup.py build_ext --inplace" ] }, { "cell_type": "code", "execution_count": 13, "id": "76b5d144-63e8-43fc-af4f-f5c5cdeeefb7", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "# L-15 MCS 507 Mon 25 Sep 2023 : integral4pi_typed_apply.py\n", "\n", "\"\"\"\n", "This script applies the composite trapezoidal rule\n", "to the integral of sqrt(1-x^2) for x from 0 to 1,\n", "to obtain an approximation for Pi.\n", "\"\"\"\n", "\n", "from time import perf_counter\n", "from integral4pi_typed import integral4pi\n", "\n", "START_TIME = perf_counter()\n", "APPROX = integral4pi(10**8)\n", "STOP_TIME = perf_counter()\n", "print('pi =', APPROX)\n", "ELAPSED = STOP_TIME - START_TIME\n", "print('elapsed time = %.3f seconds' % ELAPSED)\n" ] } ], "source": [ "with open('integral4pi_typed_apply.py') as f:\n", " for line in f.readlines():\n", " print(line[:-1])" ] }, { "cell_type": "code", "execution_count": 14, "id": "75e6e733-511e-4849-b890-aa97ef7c91e1", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "pi = 3.141592693586875\n", "elapsed time = 6.555 seconds\n" ] } ], "source": [ "!python integral4pi_typed_apply.py" ] }, { "cell_type": "markdown", "id": "32cc092c-111d-402f-a007-51218eabdee0", "metadata": {}, "source": [ "Compare the difference with the previous time!" ] }, { "cell_type": "markdown", "id": "2377967b-0d47-4206-bf4b-970a27bf3db1", "metadata": {}, "source": [ "## 2.3 declaring C-style functions" ] }, { "cell_type": "code", "execution_count": 15, "id": "43b7e989-5901-45f9-a732-91e895a495c5", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "# cython: language_level=3\n", "\n", "# L-15 MCS 507 Mon 25 Sep 2023 : integral4pi_cdeffun.pyx\n", "\n", "\"\"\"\n", "This script applies the composite trapezoidal rule\n", "to the integral of sqrt(1-x^2) for x from 0 to 1,\n", "to obtain an approximation for pi.\n", "Type declarations have been added so the for loop\n", "will be compiled into pure C code.\n", "To avoid the construction of float objects around function calls,\n", "we declare a C-style function.\n", "\"\"\"\n", "\n", "from math import sqrt\n", "\n", "cdef double circle(double x) except *:\n", " return sqrt(1-x**2)\n", "\n", "def integral4pi(int nbvals):\n", " \"\"\"\n", " Approximates Pi with the trapezoidal\n", " rule with nbvals subintervals of [0,1].\n", " \"\"\"\n", " cdef int i\n", " cdef double step, result\n", " step = 1.0/nbvals\n", " result = (circle(0)+circle(1))/2\n", " for i in range(nbvals):\n", " result += circle(i*step)\n", " return 4*result*step\n" ] } ], "source": [ "with open('integral4pi_cdeffun.pyx') as f:\n", " for line in f.readlines():\n", " print(line[:-1])" ] }, { "cell_type": "markdown", "id": "f2f97a1b-112c-43f1-b211-0ce8591d8c7e", "metadata": {}, "source": [ "The instructions to compile the code defined by the file `integral4pi_cdeffun.pyx` are defined in the file `integral4pi_cdeffun_setup.py`." ] }, { "cell_type": "code", "execution_count": 16, "id": "b82b5040-c58d-4e03-aa61-ff6f4ea2fbfb", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "# L-15 MCS 507 Mon 25 Sep 2023 : integral4pi_cdeffun_setup.py\n", "\n", "\"\"\"\n", "We build the extension integral4pi_cdeffun with cython by\n", "python integral4pi_cdeffun_setup.py build_ext --inplace\n", "\"\"\"\n", "\n", "from distutils.core import setup\n", "from distutils.extension import Extension\n", "from Cython.Distutils import build_ext\n", "\n", "EXT_MODULES = [Extension(\"integral4pi_cdeffun\",\n", " [\"integral4pi_cdeffun.pyx\"])]\n", "\n", "setup(\n", " name = 'integral approximation for pi' ,\n", " cmdclass = {'build_ext': build_ext},\n", " ext_modules = EXT_MODULES\n", ")\n" ] } ], "source": [ "with open('integral4pi_cdeffun_setup.py') as f:\n", " for line in f.readlines():\n", " print(line[:-1])" ] }, { "cell_type": "code", "execution_count": 17, "id": "ce7d851c-7eb2-43e5-8233-4d8ea96d0431", "metadata": {}, "outputs": [], "source": [ "!python integral4pi_cdeffun_setup.py build_ext --inplace" ] }, { "cell_type": "code", "execution_count": 18, "id": "f47d70a4-6eb3-4630-8f33-a71577cab5e9", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "# L-15 MCS 507 Mon 25 Sep 2023 : integral4pi_cdeffun_apply.py\n", "\n", "\"\"\"\n", "This script applies the composite trapezoidal rule \n", "to the integral of sqrt(1-x^2) for x from 0 to 1,\n", "to obtain an approximation for pi.\n", "\"\"\"\n", "\n", "from time import perf_counter\n", "from integral4pi_cdeffun import integral4pi\n", "\n", "START_TIME = perf_counter()\n", "APPROX = integral4pi(10**8)\n", "STOP_TIME = perf_counter()\n", "print('pi =', APPROX)\n", "ELAPSED = STOP_TIME - START_TIME\n", "print('elapsed time = %.3f seconds' % ELAPSED)\n" ] } ], "source": [ "with open('integral4pi_cdeffun_apply.py') as f:\n", " for line in f.readlines():\n", " print(line[:-1])" ] }, { "cell_type": "code", "execution_count": 19, "id": "a9ea18e8-893e-4d2b-bcc0-b9cd270d51bf", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "pi = 3.141592693586875\n", "elapsed time = 4.778 seconds\n" ] } ], "source": [ "!python integral4pi_cdeffun_apply.py" ] }, { "cell_type": "markdown", "id": "5b968f22-5d80-4559-aee0-c71a2ff7d9f5", "metadata": {}, "source": [ "## 2.4 calling external C functions" ] }, { "cell_type": "code", "execution_count": 20, "id": "cfb2fd2d-8450-4a53-9fff-d1753e398d83", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "# cython: language_level=3\n", "\n", "# L-15 MCS 507 Mon 25 Sep 2023 : integral4pi_extcfun.pyx\n", "\n", "\"\"\"\n", "This script applies the composite trapezoidal rule\n", "to the integral of sqrt(1-x^2) for x from 0 to 1,\n", "to obtain an approximation for pi.\n", "Type declarations have been added so the for loop\n", "will be compiled into pure C code.\n", "Instead of the sqrt of the Python math library,\n", "we call the sqrt of the external C library.\n", "To avoid the construction of float objects around function calls,\n", "we declare a C-style function.\n", "\"\"\"\n", "\n", "cdef extern from \"math.h\":\n", " double sqrt(double)\n", "\n", "cdef double circle(double x) except *:\n", " return sqrt(1-x**2)\n", "\n", "def integral4pi(int nbvals):\n", " \"\"\"\n", " Approximates Pi with the trapezoidal\n", " rule with nbvals subintervals of [0,1].\n", " \"\"\"\n", " cdef int i\n", " cdef double step, result\n", " step = 1.0/nbvals\n", " result = (circle(0)+circle(1))/2\n", " for i in range(nbvals):\n", " result += circle(i*step)\n", " return 4*result*step\n" ] } ], "source": [ "with open('integral4pi_extcfun.pyx') as f:\n", " for line in f.readlines():\n", " print(line[:-1])" ] }, { "cell_type": "code", "execution_count": 21, "id": "84a6c5ea-ac06-4ccd-84f4-c6607d64f4a2", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "# L-15 MCS 507 Mon 25 Sep 2023 : integral4pi_extcfun_setup.py\n", "\n", "\"\"\"\n", "We build the shared object file integral4pi_typed.so with cython by\n", "python integral4pi_extcfun_setup.py build_ext --inplace\n", "\"\"\"\n", "\n", "from distutils.core import setup\n", "from distutils.extension import Extension\n", "from Cython.Distutils import build_ext\n", "\n", "EXT_MODULES = [Extension(\"integral4pi_extcfun\",\n", " [\"integral4pi_extcfun.pyx\"])]\n", "\n", "setup(\n", " name = 'integral approximation for pi' ,\n", " cmdclass = {'build_ext': build_ext},\n", " ext_modules = EXT_MODULES\n", ")\n" ] } ], "source": [ "with open('integral4pi_extcfun_setup.py') as f:\n", " for line in f.readlines():\n", " print(line[:-1])" ] }, { "cell_type": "code", "execution_count": 22, "id": "16964038-13a1-4d46-a13d-0db781da4c0b", "metadata": {}, "outputs": [], "source": [ "!python integral4pi_extcfun_setup.py build_ext --inplace" ] }, { "cell_type": "code", "execution_count": 23, "id": "e136ad01-0ba5-4ad3-a90f-0bf86968cf15", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "# L-15 MCS 507 Mon 25 Sep 2023 : integral4pi_extcfun_apply.py\n", "\n", "\"\"\"\n", "This script applies the composite trapezoidal rule\n", "to the integral of sqrt(1-x^2) for x from 0 to 1,\n", "to obtain an approximation for pi.\n", "\"\"\"\n", "\n", "from time import perf_counter\n", "from integral4pi_extcfun import integral4pi\n", "\n", "START_TIME = perf_counter()\n", "APPROX = integral4pi(10**8)\n", "STOP_TIME = perf_counter()\n", "print('pi =', APPROX)\n", "ELAPSED = STOP_TIME - START_TIME\n", "print('elapsed time = %.3f seconds' % ELAPSED)\n" ] } ], "source": [ "with open('integral4pi_extcfun_apply.py') as f:\n", " for line in f.readlines():\n", " print(line[:-1])" ] }, { "cell_type": "code", "execution_count": 24, "id": "19819e89-d744-4664-aac7-bdbf34c6bb0a", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "pi = 3.141592693586875\n", "elapsed time = 1.450 seconds\n" ] } ], "source": [ "import integral4pi_extcfun_apply" ] }, { "cell_type": "markdown", "id": "2e53e9b4-172f-4805-bfe2-d5ea3196cd12", "metadata": {}, "source": [ "# 2.5 summarizing all runs" ] }, { "cell_type": "code", "execution_count": 25, "id": "1603a6ab-be44-49e5-b60f-bee773b6ff04", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "*** running pure Python :\n", "pi = 3.141592693586875\n", "elapsed time = 19.378 seconds\n", "*** adding type declarations :\n", "pi = 3.141592693586875\n", "elapsed time = 6.563 seconds\n", "*** declaring C style functions :\n", "pi = 3.141592693586875\n", "elapsed time = 4.746 seconds\n", "*** calling external C functions :\n", "pi = 3.141592693586875\n", "elapsed time = 1.362 seconds\n" ] } ], "source": [ "print('*** running pure Python :')\n", "!python integral4pi.py\n", "print('*** adding type declarations :')\n", "!python integral4pi_typed_apply.py\n", "print('*** declaring C style functions :')\n", "!python integral4pi_cdeffun_apply.py\n", "print('*** calling external C functions :')\n", "!python integral4pi_extcfun_apply.py" ] }, { "cell_type": "markdown", "id": "af3f19f2-0794-418b-88e5-31b489e8ad72", "metadata": {}, "source": [ "# 3. Conway's Game of Life" ] }, { "cell_type": "markdown", "id": "4295e81a-c815-4917-9934-f1e6f6e20486", "metadata": {}, "source": [ "The rules of the game of life of Conway are as follows.\n", "\n", "Consider a rectangular grid of cells:\n", "\n", "1. An empty cell is born when it has 3 neighbors.\n", "\n", "2. A living cell can either die or survive, as follows\n", "\n", " 1. die by loneliness, if the cell has one or no neighbors;\n", "\n", " 2. die by overpopulation, if the cell has $\\geq 4$ neighbors;\n", "\n", " 3. survive, if the cell has two or three neighbors." ] }, { "cell_type": "markdown", "id": "6b7b68d3-30e5-49e8-ac7d-483a91dbbfa4", "metadata": {}, "source": [ "In every update, the grid is traversed and the number of neighbors are computed for every cell of the grid. In the Cython version, type declarations are added in the function which computes the number of neighbors of each cell." ] }, { "cell_type": "markdown", "id": "a2c11c30-ea52-466c-bfc5-3e16cffdc396", "metadata": {}, "source": [ "The code below runs without the visualizations." ] }, { "cell_type": "code", "execution_count": 26, "id": "69db142a-2d5c-494e-8dc7-d4be9d6ac668", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "elapsed time 8.88484840001911 seconds\n" ] } ], "source": [ "!python run_game_of_life.py" ] }, { "cell_type": "code", "execution_count": 27, "id": "f31f9a96-3f0d-4037-b388-2008936e9a74", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Compiling run_game_better.pyx because it changed.\n", "[1/1] Cythonizing run_game_better.pyx\n", "run_game_better.c\n", "C:\\Users\\jan\\miniconda3\\lib\\site-packages\\numpy\\core\\include\\numpy\\npy_1_7_deprecated_api.h(14) : Warning Msg: Using deprecated NumPy API, disable it with #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\n", " Creating library build\\temp.win-amd64-cpython-310\\Release\\run_game_better.cp310-win_amd64.lib and object build\\temp.win-amd64-cpython-310\\Release\\run_game_better.cp310-win_amd64.exp\n", "Generating code\n", "Finished generating code\n" ] } ], "source": [ "!python run_game_better_setup.py build_ext --inplace" ] }, { "cell_type": "code", "execution_count": 28, "id": "2ae7da29-6c39-4c1c-be69-aa3931df1b0b", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "elapsed time 0.6083413999294862 seconds\n" ] } ], "source": [ "!python run_game_better_apply.py" ] }, { "cell_type": "markdown", "id": "af833ee6-7b99-4788-98cc-136e65266e55", "metadata": {}, "source": [ "Observe the speedup." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "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.10" } }, "nbformat": 4, "nbformat_minor": 5 }