{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Tutorial A8 – Solutions" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "__1__ Write a functions that takes two numbers as input and returns the sum." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "3\n" ] } ], "source": [ "def calc_sum(a, b):\n", " \"\"\"Calculate the sum of two values\"\"\"\n", " \n", " return a + b\n", "\n", "print(calc_sum(1, 2))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "__2__ Write a function that computes the cumulative sum of values in a sequence and returns the result as a list. Demonstrate that it works. Hint: You can use a list to pass a sequence to a function." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[0, 1, 3, 6, 10, 15, 21, 28, 36, 45]\n" ] } ], "source": [ "def cumsum(seq):\n", " \"\"\"Compute cumulative sum\n", " \n", " Args:\n", " seq: Sequence of numbers\n", " \n", " Returns:\n", " Cumulative sum as list\n", " \"\"\"\n", " \n", " result = []\n", " for i, _ in enumerate(seq, 1):\n", " result.append(\n", " sum(seq[:i])\n", " )\n", " return result\n", "\n", "print(cumsum(range(10)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "__3__ Write a function `factorial(n)` that returns the factorial of an integer $n$. What happens if you pass a float?" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "def factorial(n):\n", " \"\"\"Compute the factorial of an integer\"\"\"\n", " \n", " product = 1\n", " while n > 1:\n", " product *= n\n", " n -= 1\n", " \n", " return product" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1\n", "1\n", "2\n", "6\n", "24\n" ] } ], "source": [ "# Function returns the correct answer\n", "for i in range(5):\n", " print(factorial(i))" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "3.36\n" ] } ], "source": [ "# Function returns nonsense if you pass a float\n", "print(factorial(2.4))" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "# How to ensure n is an integer?\n", "def factorial_save(n):\n", " \"\"\"Compute the factorial of an integer\"\"\"\n", " \n", " assert isinstance(n, int)\n", " # Raise an error if n is not an int\n", " \n", " product = 1\n", " while n > 1:\n", " product *= n\n", " n -= 1\n", " \n", " return product" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "ename": "AssertionError", "evalue": "", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mAssertionError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;31m# Function raises an error if n is not an int\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfactorial_save\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m2.4\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;32m\u001b[0m in \u001b[0;36mfactorial_save\u001b[0;34m(n)\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;34m\"\"\"Compute the factorial of an integer\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 5\u001b[0;31m \u001b[0;32massert\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mint\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 6\u001b[0m \u001b[0;31m# Raise an error if n is not an int\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 7\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mAssertionError\u001b[0m: " ] } ], "source": [ "# Function raises an error if n is not an int\n", "print(factorial_save(2.4))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "__Advanced 1__ Write a function `exp(x)` that takes a float `x` \n", "as an argument and returns $\\mathrm{e}^x$ approximated as the Taylor series up to order $n$ around the expansion point $a = 0$. Make the order $n$ an optional argument that defaults to $n = 5$. You can call `factorial(n)` from within `exp(x)` to calculate the factorials." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "$$T(x; a) = \\sum_{n = 0}^\\infty \\frac{f^{(n)}(a)}{n!} (x - a)^n$$" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For $f(x) = \\mathrm{e}^x$, $a = 0$:\n", "\n", "$$T(x; 0) = \\sum_{n = 0}^\\infty \\frac{x^{n}}{n!}$$" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "def exp(x, n=5):\n", " \"\"\"Calculate e**x approximated by a Taylor expansion around 0\n", " \n", " Args:\n", " x (float): Input value\n", " n (int): Expansion order\n", " \n", " Returns:\n", " Result (float) \n", " \"\"\"\n", " \n", " assert isinstance(n, int)\n", " \n", " result = 1 # Zero order approximation\n", " for i in range(1, n+1):\n", " # Add term\n", " result += x ** i / factorial(i)\n", " \n", " return result" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "run_control": { "marked": true } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0.3666666666666667\n", "0.40591675000000005\n", "0.44900266666666666\n", "0.49643691666666656\n", "0.5487519999999999\n", "0.6065104166666666\n", "0.6703146666666665\n", "0.74081725\n", "0.8187306666666667\n", "0.9048374166666667\n", "1.0\n", "1.1051709166666666\n", "1.2214026666666666\n", "1.34985775\n", "1.4918186666666666\n", "1.6486979166666667\n", "1.8220480000000003\n", "2.013571416666667\n", "2.225130666666667\n", "2.45875825\n", "2.7166666666666663\n" ] } ], "source": [ "# Generate 21 values in the open interval (-1, 1)\n", "x = [x*0.1 for x in range(-10, 11)]\n", "\n", "# Call our function (default n = 5)\n", "for x_ in x:\n", " print(exp(x_))" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0.5\n", "0.505\n", "0.52\n", "0.5449999999999999\n", "0.58\n", "0.625\n", "0.6799999999999999\n", "0.745\n", "0.8200000000000001\n", "0.905\n", "1.0\n", "1.105\n", "1.22\n", "1.345\n", "1.48\n", "1.625\n", "1.7800000000000002\n", "1.9450000000000003\n", "2.12\n", "2.3049999999999997\n", "2.5\n" ] } ], "source": [ "# Call our function (lower order)\n", "for x_ in x:\n", " print(exp(x_, n=2))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "__Advanced 2__ What is wrong with these two functions:" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [], "source": [ "def broken():\n", " print(x)\n", " x = \"NEW\"\n", " \n", " return(x)\n", "\n", "x = \"STRING\"" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "run_control": { "marked": true } }, "outputs": [], "source": [ "def broken_counter():\n", " counter += 1\n", "\n", "counter = 1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "__Advanced 3__ (Warning: the solution to this problem touches a concept we have not discussed in the lesson. This is a really advanced exercise.) Ever solved a \"Jumble\"-puzzle? Write a function that expects a string\n", "and returns every possible re-combination of the letters to help you find\n", "the terms hidden behind \"rta\", \"atob\" and \"rbani\". You can test your function with the built-in function\n", "`itertools.permutations` from the `itertools` module. How many possible combinations does this return?\n", "Does the solver help you with this one: \"ibaptlienxraoc\"? Hint: Functions can call themselves. Try to pick letters from the string one by one to find a possible re-combination. " ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "scrolled": true }, "outputs": [], "source": [ "# Solution using recursion\n", "def recombine(pool, combination=''):\n", " if len(pool) == 0:\n", " # Pool exhausted, combination found\n", " combinations.append(combination)\n", " else:\n", " for i in range(len(pool)):\n", " # Take out one element and append it to combination\n", " recombine(pool[0:i] + pool[i + 1:], combination + pool[i])" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "rta rat tra tar art atr\n" ] } ], "source": [ "combinations = [] \n", "recombine(\"rta\")\n", "print(*combinations, sep=\" \")" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "atob atbo aotb aobt abto abot taob tabo toab toba tbao tboa oatb oabt otab otba obat obta bato baot btao btoa boat bota\n" ] } ], "source": [ "combinations = [] \n", "recombine(\"atob\")\n", "print(*combinations, sep=\" \")" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "rbani rbain rbnai rbnia rbian rbina rabni rabin ranbi ranib raibn rainb rnbai rnbia rnabi rnaib rniba rniab riban ribna riabn rianb rinba rinab brani brain brnai brnia brian brina barni barin banri banir bairn bainr bnrai bnria bnari bnair bnira bniar biran birna biarn bianr binra binar arbni arbin arnbi arnib aribn arinb abrni abrin abnri abnir abirn abinr anrbi anrib anbri anbir anirb anibr airbn airnb aibrn aibnr ainrb ainbr nrbai nrbia nrabi nraib nriba nriab nbrai nbria nbari nbair nbira nbiar narbi narib nabri nabir nairb naibr nirba nirab nibra nibar niarb niabr irban irbna irabn iranb irnba irnab ibran ibrna ibarn ibanr ibnra ibnar iarbn iarnb iabrn iabnr ianrb ianbr inrba inrab inbra inbar inarb inabr\n" ] } ], "source": [ "combinations = [] \n", "recombine(\"rbani\")\n", "print(*combinations, sep=\" \")" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "rta rat tra tar art atr\n" ] } ], "source": [ "# Test with built-in function \n", "import itertools\n", "\n", "print(*[\"\".join(x) for x in itertools.permutations(\"rta\")], sep=\" \")" ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "scrolled": true }, "outputs": [ { "data": { "text/plain": [ "87178291200" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# The number of possible recombinations growths fast (n!)\n", "import math\n", "\n", "math.factorial(len(\"ibaptlienxraoc\"))" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "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.8.1" }, "toc": { "base_numbering": 1, "nav_menu": {}, "number_sections": true, "sideBar": true, "skip_h1_title": false, "title_cell": "Table of Contents", "title_sidebar": "Contents", "toc_cell": false, "toc_position": {}, "toc_section_display": true, "toc_window_display": false } }, "nbformat": 4, "nbformat_minor": 4 }