diff --git a/episodes/notebooks/README.md b/episodes/notebooks/README.md new file mode 100644 index 00000000..c3aac365 --- /dev/null +++ b/episodes/notebooks/README.md @@ -0,0 +1,2 @@ +This repo contains a list of jupyter notebooks which will be associated to each of the episodes. +They will help instructors preparing and teaching the carpentry course diff --git a/episodes/notebooks/optimisation-data-structures-algorithms.ipynb b/episodes/notebooks/optimisation-data-structures-algorithms.ipynb new file mode 100644 index 00000000..7c499616 --- /dev/null +++ b/episodes/notebooks/optimisation-data-structures-algorithms.ipynb @@ -0,0 +1,158 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "3b8b3bc6", + "metadata": {}, + "outputs": [], + "source": [ + "from timeit import timeit\n", + "\n", + "def list_append():\n", + " li = []\n", + " for i in range(100000):\n", + " li.append(i)\n", + "\n", + "def list_preallocate():\n", + " li = [0]*100000\n", + " for i in range(100000):\n", + " li[i] = i\n", + "\n", + "def list_comprehension():\n", + " li = [i for i in range(100000)]\n", + "\n", + "repeats = 1000\n", + "print(f\"Append: {timeit(list_append, number=repeats):.2f}ms\")\n", + "print(f\"Preallocate: {timeit(list_preallocate, number=repeats):.2f}ms\")\n", + "print(f\"Comprehension: {timeit(list_comprehension, number=repeats):.2f}ms\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "31a74be6", + "metadata": {}, + "outputs": [], + "source": [ + "class MyKey:\n", + "\n", + " def __init__(self, _a, _b, _c):\n", + " self.a = _a\n", + " self.b = _b\n", + " self.c = _c\n", + "\n", + " def __eq__(self, other):\n", + " return (isinstance(other, type(self))\n", + " and (self.a, self.b, self.c) == (other.a, other.b, other.c))\n", + "\n", + " def __hash__(self):\n", + " return hash((self.a, self.b, self.c))\n", + "\n", + "dict = {}\n", + "dict[MyKey(\"one\", 2, 3.0)] = 12" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8bbf7001", + "metadata": {}, + "outputs": [], + "source": [ + "import random\n", + "from timeit import timeit\n", + "\n", + "def generateInputs(N = 25000):\n", + " random.seed(12) # Ensure every list is the same \n", + " return [random.randint(0,int(N/2)) for i in range(N)]\n", + " \n", + "def uniqueSet():\n", + " ls_in = generateInputs()\n", + " set_out = set(ls_in)\n", + " \n", + "def uniqueSetAdd():\n", + " ls_in = generateInputs()\n", + " set_out = set()\n", + " for i in ls_in:\n", + " set_out.add(i)\n", + " \n", + "def uniqueList():\n", + " ls_in = generateInputs()\n", + " ls_out = []\n", + " for i in ls_in:\n", + " if not i in ls_out:\n", + " ls_out.append(i)\n", + "\n", + "def uniqueListSort():\n", + " ls_in = generateInputs()\n", + " ls_in.sort()\n", + " ls_out = [ls_in[0]]\n", + " for i in ls_in:\n", + " if ls_out[-1] != i:\n", + " ls_out.append(i)\n", + " \n", + "repeats = 1000\n", + "gen_time = timeit(generateInputs, number=repeats)\n", + "print(f\"uniqueSet: {timeit(uniqueSet, number=repeats)-gen_time:.2f}ms\")\n", + "print(f\"uniqueSetAdd: {timeit(uniqueSetAdd, number=repeats)-gen_time:.2f}ms\")\n", + "print(f\"uniqueList: {timeit(uniqueList, number=repeats)-gen_time:.2f}ms\")\n", + "print(f\"uniqueListSort: {timeit(uniqueListSort, number=repeats)-gen_time:.2f}ms\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "63d3eb19", + "metadata": {}, + "outputs": [], + "source": [ + "import random\n", + "from timeit import timeit\n", + "from bisect import bisect_left\n", + "\n", + "N = 25000 # Number of elements in list\n", + "M = 2 # N*M == Range over which the elements span\n", + "\n", + "def generateInputs():\n", + " random.seed(12) # Ensure every list is the same\n", + " st = set([random.randint(0, int(N*M)) for i in range(N)])\n", + " ls = list(st)\n", + " ls.sort() # Sort required for binary\n", + " return st, ls # Return both set and list\n", + " \n", + "def search_set():\n", + " st, _ = generateInputs()\n", + " j = 0\n", + " for i in range(0, int(N*M), M):\n", + " if i in st:\n", + " j += 1\n", + " \n", + "def linear_search_list():\n", + " _, ls = generateInputs()\n", + " j = 0\n", + " for i in range(0, int(N*M), M):\n", + " if i in ls:\n", + " j += 1\n", + " \n", + "def binary_search_list():\n", + " _, ls = generateInputs()\n", + " j = 0\n", + " for i in range(0, int(N*M), M):\n", + " k = bisect_left(ls, i)\n", + " if k != len(ls) and ls[k] == i:\n", + " j += 1\n", + "\n", + " \n", + "repeats = 1000\n", + "gen_time = timeit(generateInputs, number=repeats)\n", + "print(f\"search_set: {timeit(search_set, number=repeats)-gen_time:.2f}ms\")\n", + "print(f\"linear_search_list: {timeit(linear_search_list, number=repeats)-gen_time:.2f}ms\")\n", + "print(f\"binary_search_list: {timeit(binary_search_list, number=repeats)-gen_time:.2f}ms\")" + ] + } + ], + "metadata": {}, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/episodes/notebooks/optimisation-introduction.ipynb b/episodes/notebooks/optimisation-introduction.ipynb new file mode 100644 index 00000000..679da69c --- /dev/null +++ b/episodes/notebooks/optimisation-introduction.ipynb @@ -0,0 +1,38 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "6438a865", + "metadata": {}, + "outputs": [], + "source": [ + "# Python code\n", + "a = 1\n", + "b = 2\n", + "c = a + b" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b38dca50", + "metadata": {}, + "outputs": [], + "source": [ + "# file: test_demonstration.py\n", + "\n", + "# A simple function to be tested, this could instead be an imported package\n", + "def squared(x):\n", + " return x**2\n", + "\n", + "# A simple test case\n", + "def test_example():\n", + " assert squared(5) == 24" + ] + } + ], + "metadata": {}, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/episodes/notebooks/optimisation-latency.ipynb b/episodes/notebooks/optimisation-latency.ipynb new file mode 100644 index 00000000..31f9dcc8 --- /dev/null +++ b/episodes/notebooks/optimisation-latency.ipynb @@ -0,0 +1,122 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "f620fe00", + "metadata": {}, + "outputs": [], + "source": [ + "import os, time\n", + "\n", + "# Generate 10MB\n", + "data_len = 10000000\n", + "data = os.urandom(data_len)\n", + "file_ct = 1000\n", + "file_len = int(data_len/file_ct)\n", + "# Write one large file\n", + "start = time.perf_counter()\n", + "large_file = open(\"large.bin\", \"wb\")\n", + "large_file.write(data)\n", + "large_file.close ()\n", + "large_write_s = time.perf_counter() - start\n", + "# Write multiple small files\n", + "start = time.perf_counter()\n", + "for i in range(file_ct):\n", + " small_file = open(f\"small_{i}.bin\", \"wb\")\n", + " small_file.write(data[file_len*i:file_len*(i+1)])\n", + " small_file.close()\n", + "small_write_s = time.perf_counter() - start\n", + "# Read back the large file\n", + "start = time.perf_counter()\n", + "large_file = open(\"large.bin\", \"rb\")\n", + "t = large_file.read(data_len)\n", + "large_file.close ()\n", + "large_read_s = time.perf_counter() - start\n", + "# Read back the small files\n", + "start = time.perf_counter()\n", + "for i in range(file_ct):\n", + " small_file = open(f\"small_{i}.bin\", \"rb\")\n", + " t = small_file.read(file_len)\n", + " small_file.close()\n", + "small_read_s = time.perf_counter() - start\n", + "# Print Summary\n", + "print(f\"{1:5d}x{data_len/1000000}MB Write: {large_write_s:.5f} seconds\")\n", + "print(f\"{file_ct:5d}x{file_len/1000}KB Write: {small_write_s:.5f} seconds\")\n", + "print(f\"{1:5d}x{data_len/1000000}MB Read: {large_read_s:.5f} seconds\")\n", + "print(f\"{file_ct:5d}x{file_len/1000}KB Read: {small_read_s:.5f} seconds\")\n", + "print(f\"{file_ct:5d}x{file_len/1000}KB Write was {small_write_s/large_write_s:.1f} slower than 1x{data_len/1000000}MB Write\")\n", + "print(f\"{file_ct:5d}x{file_len/1000}KB Read was {small_read_s/large_read_s:.1f} slower than 1x{data_len/1000000}MB Read\")\n", + "# Cleanup\n", + "os.remove(\"large.bin\")\n", + "for i in range(file_ct):\n", + " os.remove(f\"small_{i}.bin\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "217267af", + "metadata": {}, + "outputs": [], + "source": [ + "grid_shape = (512, 512)\n", + "\n", + "def update(grid, a_dt):\n", + " x_max, y_max = grid_shape\n", + " out_grid = [[0.0 for x in range(y_max)] * y_max for x in range(x_max)]\n", + " for i in range(x_max):\n", + " for j in range(y_max):\n", + " out_xx = grid[(i-1)%x_max][j] - 2 * grid[i][j] + grid[(i+1)%x_max][j]\n", + " out_yy = grid[i][(j-1)%y_max] - 2 * grid[i][j] + grid[i][(j+1)%y_max]\n", + " out_grid[i][j] = grid[i][j] + (out_xx + out_yy) * a_dt \n", + " return out_grid\n", + " \n", + "def heat_equation(steps):\n", + " x_max, y_max = grid_shape\n", + " grid = [[0.0] * y_max for x in range(x_max)]\n", + " # Init central point to diffuse\n", + " grid[int(x_max/2)][int(y_max/2)] = 1.0\n", + " # Run steps\n", + " for i in range(steps):\n", + " grid = update(grid, 0.1)\n", + "\n", + "heat_equation(100)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d0809621", + "metadata": {}, + "outputs": [], + "source": [ + "grid_shape = (512, 512)\n", + "\n", + "def update(grid, a_dt, out_grid):\n", + " x_max, y_max = grid_shape\n", + " for i in range(x_max):\n", + " for j in range(y_max):\n", + " out_xx = grid[(i-1)%x_max][j] - 2 * grid[i][j] + grid[(i+1)%x_max][j]\n", + " out_yy = grid[i][(j-1)%y_max] - 2 * grid[i][j] + grid[i][(j+1)%y_max]\n", + " out_grid[i][j] = grid[i][j] + (out_xx + out_yy) * a_dt \n", + " \n", + "def heat_equation(steps):\n", + " x_max, y_max = grid_shape\n", + " grid = [[0.0 for x in range(y_max)] for x in range(x_max)]\n", + " out_grid = [[0.0 for x in range(y_max)] for x in range(x_max)] # Allocate a second buffer once\n", + " # Init central point to diffuse\n", + " grid[int(x_max/2)][int(y_max/2)] = 1.0\n", + " # Run steps\n", + " for i in range(steps):\n", + " update(grid, 0.1, out_grid) # Pass the output buffer\n", + " grid, out_grid = out_grid, grid # Swap buffers\n", + "\n", + "heat_equation(100)" + ] + } + ], + "metadata": {}, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/episodes/notebooks/optimisation-numpy.ipynb b/episodes/notebooks/optimisation-numpy.ipynb new file mode 100644 index 00000000..9d6a8edd --- /dev/null +++ b/episodes/notebooks/optimisation-numpy.ipynb @@ -0,0 +1,173 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "ff046953", + "metadata": {}, + "outputs": [], + "source": [ + "from timeit import timeit\n", + "import numpy\n", + "\n", + "N = 100000 # Number of elements in list/array\n", + "\n", + "def list_append():\n", + " ls = []\n", + " for i in range(N):\n", + " ls.append(i)\n", + "\n", + "def array_resize():\n", + " ar = numpy.zeros(1)\n", + " for i in range(1, N):\n", + " ar.resize(i+1)\n", + " ar[i] = i\n", + " \n", + "repeats = 1000\n", + "print(f\"list_append: {timeit(list_append, number=repeats):.2f}ms\")\n", + "print(f\"array_resize: {timeit(array_resize, number=repeats):.2f}ms\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "614a7d9d", + "metadata": {}, + "outputs": [], + "source": [ + "from timeit import timeit\n", + "\n", + "N = 1000000 # Number of elements in list\n", + "\n", + "gen_list = f\"ls = list(range({N}))\"\n", + "gen_array = f\"import numpy; ar = numpy.arange({N}, dtype=numpy.int64)\"\n", + "\n", + "py_sum_ls = \"sum([i*i for i in ls])\"\n", + "py_sum_ar = \"sum(ar*ar)\"\n", + "np_sum_ar = \"numpy.sum(ar*ar)\"\n", + "np_dot_ar = \"numpy.dot(ar, ar)\"\n", + "\n", + "repeats = 1000\n", + "print(f\"python_sum_list: {timeit(py_sum_ls, setup=gen_list, number=repeats):.2f}ms\")\n", + "print(f\"python_sum_array: {timeit(py_sum_ar, setup=gen_array, number=repeats):.2f}ms\")\n", + "print(f\"numpy_sum_array: {timeit(np_sum_ar, setup=gen_array, number=repeats):.2f}ms\")\n", + "print(f\"numpy_dot_array: {timeit(np_dot_ar, setup=gen_array, number=repeats):.2f}ms\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f6e557eb", + "metadata": {}, + "outputs": [], + "source": [ + "from timeit import timeit\n", + "import pandas\n", + "import numpy\n", + "\n", + "N = 100000 # Number of rows in DataFrame\n", + "\n", + "def genDataFrame():\n", + " numpy.random.seed(12) # Ensure each dataframe is identical\n", + " return pandas.DataFrame(\n", + " {\n", + " \"f_vertical\": numpy.random.random(size=N),\n", + " \"f_horizontal\": numpy.random.random(size=N),\n", + " # todo some spurious columns\n", + " })\n", + "\n", + "def pythagoras(row):\n", + " return (row[\"f_vertical\"]**2 + row[\"f_horizontal\"]**2)**0.5\n", + " \n", + "def for_range():\n", + " rtn = []\n", + " df = genDataFrame()\n", + " for row_idx in range(df.shape[0]):\n", + " row = df.iloc[row_idx]\n", + " rtn.append(pythagoras(row))\n", + " return pandas.Series(rtn)\n", + "\n", + "def for_iterrows():\n", + " rtn = []\n", + " df = genDataFrame()\n", + " for row_idx, row in df.iterrows():\n", + " rtn.append(pythagoras(row))\n", + " return pandas.Series(rtn)\n", + " \n", + "def pandas_apply():\n", + " df = genDataFrame()\n", + " return df.apply(pythagoras, axis=1)\n", + "\n", + "repeats = 100\n", + "gentime = timeit(genDataFrame, number=repeats)\n", + "print(f\"for_range: {timeit(for_range, number=repeats)*10-gentime:.2f}ms\")\n", + "print(f\"for_iterrows: {timeit(for_iterrows, number=repeats)*10-gentime:.2f}ms\")\n", + "print(f\"pandas_apply: {timeit(pandas_apply, number=repeats)*10-gentime:.2f}ms\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "003d088d", + "metadata": {}, + "outputs": [], + "source": [ + "def vectorize():\n", + " df = genDataFrame()\n", + " return pandas.Series(numpy.sqrt(numpy.square(df[\"f_vertical\"]) + numpy.square(df[\"f_horizontal\"])))\n", + " \n", + "print(f\"vectorize: {timeit(vectorize, number=repeats)-gentime:.2f}ms\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fd73ffc8", + "metadata": {}, + "outputs": [], + "source": [ + "def to_dict():\n", + " df = genDataFrame()\n", + " df_as_dict = df.to_dict(orient='index')\n", + " return pandas.Series([(r['f_vertical']**2 + r['f_horizontal']**2)**0.5 for r in df_as_dict.values()])\n", + "\n", + "print(f\"to_dict: {timeit(to_dict, number=repeats)*10-gentime:.2f}ms\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a26495a2", + "metadata": {}, + "outputs": [], + "source": [ + "from timeit import timeit\n", + "import pandas as pandas\n", + "\n", + "N = 100000 # Number of rows in DataFrame\n", + "\n", + "def genInput():\n", + " s = pandas.Series({'a' : 1, 'b' : 2})\n", + " d = {'a' : 1, 'b' : 2}\n", + " return s, d\n", + "\n", + "def series():\n", + " s, _ = genInput()\n", + " for i in range(N):\n", + " y = s['a'] * s['b']\n", + "\n", + "def dictionary():\n", + " _, d = genInput()\n", + " for i in range(N):\n", + " y = d['a'] * d['b']\n", + "\n", + "repeats = 1000\n", + "print(f\"series: {timeit(series, number=repeats):.2f}ms\")\n", + "print(f\"dictionary: {timeit(dictionary, number=repeats):.2f}ms\")" + ] + } + ], + "metadata": {}, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/episodes/notebooks/optimisation-using-python.ipynb b/episodes/notebooks/optimisation-using-python.ipynb new file mode 100644 index 00000000..daf5aafb --- /dev/null +++ b/episodes/notebooks/optimisation-using-python.ipynb @@ -0,0 +1,121 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "b60e913e", + "metadata": {}, + "outputs": [], + "source": [ + "import random\n", + "\n", + "N = 2500 # Number of elements in list\n", + "M = 2 # N*M == Range over which the elements span\n", + "\n", + "def generateInputs():\n", + " random.seed(12) # Ensure every list is the same\n", + " return [random.randint(0, int(N*M)) for i in range(N)]\n", + " \n", + "def manualSearch():\n", + " ls = generateInputs()\n", + " ct = 0\n", + " for i in range(0, int(N*M), M):\n", + " for j in range(0, len(ls)):\n", + " if ls[j] == i:\n", + " ct += 1\n", + " break\n", + "\n", + "def operatorSearch():\n", + " ls = generateInputs()\n", + " ct = 0\n", + " for i in range(0, int(N*M), M):\n", + " if i in ls:\n", + " ct += 1\n", + "\n", + "repeats = 1000\n", + "gen_time = timeit(generateInputs, number=repeats)\n", + "print(f\"manualSearch: {timeit(manualSearch, number=repeats)-gen_time:.2f}ms\")\n", + "print(f\"operatorSearch: {timeit(operatorSearch, number=repeats)-gen_time:.2f}ms\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ddddf979", + "metadata": {}, + "outputs": [], + "source": [ + "f = [\n", + " ' 0000 0.9819 ',\n", + " ' 0001 0.3435 ',\n", + " # ...\n", + " ' 0099 0.2275 ',\n", + " ' 0100 0.7067 ',\n", + " # ...\n", + "]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0622809b", + "metadata": {}, + "outputs": [], + "source": [ + "def manualSplit():\n", + " data = {}\n", + " for line in f:\n", + " first_char = line.find(\"0\")\n", + " end_time = line.find(\" \", first_char, -1)\n", + "\n", + " energy_found = line.find(\".\", end_time, -1)\n", + " begin_energy = line.rfind(\" \", end_time, energy_found)\n", + " end_energy = line.find(\" \", energy_found)\n", + " if end_energy == -1:\n", + " end_energy = len(line)\n", + " \n", + " time = line[first_char:end_time]\n", + " energy = line[begin_energy + 1:end_energy]\n", + "\n", + " data[time] = energy\n", + " return data" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "955129da", + "metadata": {}, + "outputs": [], + "source": [ + "def builtinSplit():\n", + " data = {}\n", + " for line in f:\n", + " time, energy = line.split()\n", + " data[time] = energy\n", + " return data" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "957d219a", + "metadata": {}, + "outputs": [], + "source": [ + "N = 10_000 # Number of elements in the list\n", + "\n", + "# Ensure every list is the same\n", + "random.seed(12)\n", + "f = [f\" {i:0>6d} {random.random():8.4f} \" for i in range(N)]\n", + "\n", + "repeats = 1000\n", + "print(f\"manualSplit: {timeit(manualSplit, globals=globals(), number=repeats):.3f}ms\")\n", + "print(f\"builtinSplit: {timeit(builtinSplit, globals=globals(), number=repeats):.3f}ms\")" + ] + } + ], + "metadata": {}, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/episodes/notebooks/profiling-functions.ipynb b/episodes/notebooks/profiling-functions.ipynb new file mode 100644 index 00000000..66c3fcf5 --- /dev/null +++ b/episodes/notebooks/profiling-functions.ipynb @@ -0,0 +1,65 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "7a05824c", + "metadata": {}, + "outputs": [], + "source": [ + "import traceback\n", + "\n", + "def a():\n", + " b1()\n", + " b2()\n", + "def b1():\n", + " pass\n", + "def b2():\n", + " c()\n", + "def c():\n", + " traceback.print_stack()\n", + "\n", + "a()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "41fb909e", + "metadata": {}, + "outputs": [], + "source": [ + "import time\n", + "\n", + "def a_1():\n", + " for i in range(3):\n", + " b_1()\n", + " time.sleep(1)\n", + " b_2()\n", + " \n", + "def b_1():\n", + " c_1()\n", + " c_2()\n", + "\n", + "def b_2():\n", + " time.sleep(1)\n", + " \n", + "def c_1():\n", + " time.sleep(0.5)\n", + "\n", + "def c_2():\n", + " time.sleep(0.3)\n", + " d_1()\n", + "\n", + "def d_1():\n", + " time.sleep(0.1)\n", + "\n", + "# Entry Point\n", + "a_1()" + ] + } + ], + "metadata": {}, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/episodes/notebooks/profiling-lines.ipynb b/episodes/notebooks/profiling-lines.ipynb new file mode 100644 index 00000000..237bf44a --- /dev/null +++ b/episodes/notebooks/profiling-lines.ipynb @@ -0,0 +1,187 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "abc7d375", + "metadata": {}, + "outputs": [], + "source": [ + "def is_prime(number):\n", + " if number < 2:\n", + " return False\n", + " for i in range(2, int(number**0.5) + 1):\n", + " if number % i == 0:\n", + " return False\n", + " return True\n", + " \n", + "print(is_prime(1087))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a613aa11", + "metadata": {}, + "outputs": [], + "source": [ + "from line_profiler import profile\n", + "\n", + "@profile\n", + "def is_prime(number):\n", + " if number < 2:\n", + " return False\n", + " for i in range(2, int(number**0.5) + 1):\n", + " if number % i == 0:\n", + " return False\n", + " return True\n", + " \n", + "print(is_prime(1087))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "99ac3e7e", + "metadata": {}, + "outputs": [], + "source": [ + "n = 100\n", + "for i in range(1, n + 1):\n", + " if i % 3 == 0 and i % 5 == 0:\n", + " print(\"FizzBuzz\")\n", + " elif i % 3 == 0:\n", + " print(\"Fizz\")\n", + " elif i % 5 == 0:\n", + " print(\"Buzz\")\n", + " else:\n", + " print(i)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "26247123", + "metadata": {}, + "outputs": [], + "source": [ + "def fizzbuzz(n):\n", + " for i in range(1, n + 1):\n", + " if i % 3 == 0 and i % 5 == 0:\n", + " print(\"FizzBuzz\")\n", + " elif i % 3 == 0:\n", + " print(\"Fizz\")\n", + " elif i % 5 == 0:\n", + " print(\"Buzz\")\n", + " else:\n", + " print(i)\n", + "\n", + "fizzbuzz(100)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5bc18776", + "metadata": {}, + "outputs": [], + "source": [ + "from line_profiler import profile\n", + "\n", + "@profile\n", + "def fizzbuzz(n):\n", + " for i in range(1, n + 1):\n", + " if i % 3 == 0 and i % 5 == 0:\n", + " print(\"FizzBuzz\")\n", + " elif i % 3 == 0:\n", + " print(\"Fizz\")\n", + " elif i % 5 == 0:\n", + " print(\"Buzz\")\n", + " else:\n", + " print(i)\n", + "\n", + "fizzbuzz(100)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5836b7a6", + "metadata": {}, + "outputs": [], + "source": [ + "import sys\n", + "import random\n", + "from line_profiler import profile # Import profile decorator\n", + "\n", + "@profile # Decorate the function to be profiled\n", + "def main(): # Create a simple function with the code to be profiled\n", + " # Argument parsing\n", + " if len(sys.argv) != 2:\n", + " print(\"Script expects 1 positive integer argument, %u found.\"%(len(sys.argv) - 1))\n", + " sys.exit()\n", + " n = int(sys.argv[1])\n", + " # Init\n", + " random.seed(12)\n", + " arr = [random.random() for i in range(n)]\n", + " print(\"Sorting %d elements\"%(n))\n", + " # Sort\n", + " for i in range(n - 1):\n", + " swapped = False\n", + " for j in range(0, n - i - 1):\n", + " if arr[j] > arr[j + 1]:\n", + " arr[j], arr[j + 1] = arr[j + 1], arr[j]\n", + " swapped = True\n", + " # If no two elements were swapped in the inner loop, the array is sorted\n", + " if not swapped:\n", + " break\n", + " # Validate\n", + " is_sorted = True\n", + " for i in range(n - 1):\n", + " if arr[i] > arr[i+1]:\n", + " is_sorted = False\n", + " print(\"Sorting: %s\"%(\"Passed\" if is_sorted else \"Failed\"))\n", + " \n", + "main() # Call the created function" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "82c3a8a6", + "metadata": {}, + "outputs": [], + "source": [ + "# line ~1\n", + "from line_profiler import profile" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "49a000b0", + "metadata": {}, + "outputs": [], + "source": [ + "# line ~278\n", + " @profile\n", + " def eaten(self, prey_list):" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "930d029a", + "metadata": {}, + "outputs": [], + "source": [ + "for i in range(len(prey_list)):\n", + " prey = prey_list[i]\n", + " if prey.life < PREY_HUNGER_THRESH:" + ] + } + ], + "metadata": {}, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/learners/setup.md b/learners/setup.md index b320652b..df7590dd 100644 --- a/learners/setup.md +++ b/learners/setup.md @@ -37,6 +37,12 @@ pip install pytest snakeviz line_profiler[all] numpy pandas matplotlib To complete some of the exercises you will need to use a text-editor or Python IDE, so make sure you have your favourite available. +We will be using also JupyterLab to demonstrate code during the course. To prepare, please install ipykernel and register your `py311_env` environment with JupyterLab by running the following commands: +```sh +pip install jupyterlab +conda install ipykernel -y +python -m ipykernel install --user --name py311_env --display-name py311_env +``` :::::::::::::: instructor As the instructor, you should additionally install the `shapely` package, which you may need for a brief demo during the episode on scientific Python packages.