From 93008de309abdad0ce449b4657d974dd4d629c11 Mon Sep 17 00:00:00 2001 From: Alexander Hess Date: Thu, 15 Oct 2020 18:12:43 +0200 Subject: [PATCH 1/7] Add initial version of chapter 04, part 1 --- 00_intro/00_content.ipynb | 2 +- 04_iteration/00_content.ipynb | 4919 +++++++++++++++++++++++++++++++++ README.md | 8 + 3 files changed, 4928 insertions(+), 1 deletion(-) create mode 100644 04_iteration/00_content.ipynb diff --git a/00_intro/00_content.ipynb b/00_intro/00_content.ipynb index a2e8778..dbe3f49 100644 --- a/00_intro/00_content.ipynb +++ b/00_intro/00_content.ipynb @@ -754,7 +754,7 @@ " - *Chapter 2*: [Functions & Modularization ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/02_functions/00_content.ipynb)\n", "- What is the flow of execution? How can we form sentences from words?\n", " - *Chapter 3*: [Conditionals & Exceptions ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/03_conditionals/00_content.ipynb)\n", - " - *Chapter 4*: Recursion & Looping" + " - *Chapter 4*: [Recursion & Looping ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/04_iteration/00_content.ipynb)" ] }, { diff --git a/04_iteration/00_content.ipynb b/04_iteration/00_content.ipynb new file mode 100644 index 0000000..580d340 --- /dev/null +++ b/04_iteration/00_content.ipynb @@ -0,0 +1,4919 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "**Note**: Click on \"*Kernel*\" > \"*Restart Kernel and Clear All Outputs*\" in [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) *before* reading this notebook to reset its output. If you cannot run this file on your machine, you may want to open it [in the cloud ](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/04_iteration/00_content.ipynb)." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "# Chapter 4: Recursion & Looping" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "While controlling the flow of execution with an `if` statement is a must-have building block in any programming language, it alone does not allow us to run a block of code repetitively, and we need to be able to do precisely that to write useful software.\n", + "\n", + "The `for` statement shown in some examples before might be the missing piece in the puzzle. However, we can live without it and postpone its official introduction until the second half of this chapter.\n", + "\n", + "Instead, we dive into the big idea of **iteration** by studying the concept of **recursion** first. This order is opposite to many other introductory books that only treat the latter as a nice-to-have artifact, if at all. Yet, understanding recursion sharpens one's mind and contributes to seeing problems from a different angle." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Recursion" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "A popular joke among programmers by an unknown author goes like this (cf., [discussion](https://www.quora.com/What-does-the-phrase-in-order-to-understand-recursion-you-must-first-understand-recursion-mean-to-you)):" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "> \"In order to understand **recursion**, you must first understand **recursion**.\"" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "A function that calls itself is **recursive**, and the process of executing such a function is called **recursion**.\n", + "\n", + "Recursive functions contain some form of a conditional check (e.g., `if` statement) to identify a **base case** that ends the recursion *when* reached. Otherwise, the function would keep calling itself forever.\n", + "\n", + "The meaning of the word *recursive* is similar to *circular*. However, a truly circular definition is not very helpful, and we think of a recursive function as kind of a \"circular function with a way out at the end.\"" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "### Trivial Example: Countdown" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "A rather trivial toy example illustrates the important aspects concretely: If called with any positive integer as its `n` argument, `countdown()` just prints that number and calls itself with the *new* `n` being the *old* `n` minus `1`. This continues until `countdown()` is called with `n=0`. Then, the flow of execution hits the base case, and the function calls stop." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "code_folding": [], + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "def countdown(n):\n", + " \"\"\"Print a countdown until the party starts.\n", + "\n", + " Args:\n", + " n (int): seconds until the party begins\n", + " \"\"\"\n", + " if n == 0:\n", + " print(\"Happy New Year!\")\n", + " else:\n", + " print(n)\n", + " countdown(n - 1)" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "3\n", + "2\n", + "1\n", + "Happy New Year!\n" + ] + } + ], + "source": [ + "countdown(3)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "As trivial as this seems, a lot of complexity is hidden in this implementation. In particular, the order in which objects are created and de-referenced in memory might not be apparent right away as [PythonTutor ](http://pythontutor.com/visualize.html#code=def%20countdown%28n%29%3A%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20print%28%22Happy%20new%20Year!%22%29%0A%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20print%28n%29%0A%20%20%20%20%20%20%20%20countdown%28n%20-%201%29%0A%0Acountdown%283%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false) shows: Each time `countdown()` is called, Python creates a *new* frame in the part of the memory where it manages all the names. This way, Python *isolates* all the different `n` variables from each other. As new frames are created until we reach the base case, after which the frames are destroyed in the *reversed* order, this is called a **[stack ](https://en.wikipedia.org/wiki/Stack_(abstract_data_type))** of frames in computer science terminology. In simple words, a stack is a last-in-first-out (LIFO) task queue. Each frame has a single parent frame, namely the one whose recursive function call created it." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Recursion in Mathematics" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "Recursion plays a vital role in mathematics as well, and we likely know about it from some introductory course, for example, in [combinatorics ](https://en.wikipedia.org/wiki/Combinatorics)." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "### Easy Example: [Factorial ](https://en.wikipedia.org/wiki/Factorial)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "The factorial function, denoted with the $!$ symbol, is defined as follows for all non-negative integers:" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "$$0! = 1$$\n", + "$$n! = n*(n-1)!$$" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "Whenever we find a recursive way of formulating an idea, we can immediately translate it into Python in a *naive* way (i.e., we create a *correct* program that may *not* be an *efficient* implementation yet).\n", + "\n", + "Below is a first version of `factorial()`: The `return` statement does not have to be a function's last code line, and we may indeed have several `return` statements as well." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "code_folding": [], + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [], + "source": [ + "def factorial(n):\n", + " \"\"\"Calculate the factorial of a number.\n", + "\n", + " Args:\n", + " n (int): number to calculate the factorial for\n", + "\n", + " Returns:\n", + " factorial (int)\n", + " \"\"\"\n", + " if n == 0:\n", + " return 1\n", + " else:\n", + " recurse = factorial(n - 1)\n", + " result = n * recurse\n", + " return result" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "When we read such code, it is often easier not to follow every function call (i.e., `factorial(n - 1)` here) in one's mind but assume we receive a return value as specified in the documentation. Some call this approach a **[leap of faith](http://greenteapress.com/thinkpython2/html/thinkpython2007.html#sec75)**. We practice this already whenever we call built-in functions (e.g., [print() ](https://docs.python.org/3/library/functions.html#print) or [len() ](https://docs.python.org/3/library/functions.html#len)) where we would have to read C code in many cases.\n", + "\n", + "To visualize *all* the computational steps of the exemplary `factorial(3)`, we use [PythonTutor ](http://pythontutor.com/visualize.html#code=def%20factorial%28n%29%3A%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%201%0A%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20recurse%20%3D%20factorial%28n%20-%201%29%0A%20%20%20%20%20%20%20%20result%20%3D%20n%20*%20recurse%0A%20%20%20%20%20%20%20%20return%20result%0A%0Asolution%20%3D%20factorial%283%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false): The recursion again creates a stack of frames in memory. In contrast to the previous trivial example, each frame leaves a return value in memory after it is destroyed. This return value is then assigned to the `recurse` variable within the parent frame and used to compute `result`." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "6" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "factorial(3)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "3628800" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "factorial(10)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "A Pythonista would formulate `factorial()` in a more concise way using the so-called **early exit** pattern: No `else`-clause is needed as reaching a `return` statement ends a function call *immediately*. Furthermore, we do not need the temporary variables `recurse` and `result`.\n", + "\n", + "As [PythonTutor ](http://pythontutor.com/visualize.html#code=def%20factorial%28n%29%3A%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%201%0A%20%20%20%20return%20n%20*%20factorial%28n%20-%201%29%0A%0Asolution%20%3D%20factorial%283%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false) shows, this implementation is more efficient as it only requires 18 computational steps instead of 24 to calculate `factorial(3)`, an improvement of 25 percent! " + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "def factorial(n):\n", + " \"\"\"Calculate the factorial of a number.\n", + "\n", + " Args:\n", + " n (int): number to calculate the factorial for\n", + "\n", + " Returns:\n", + " factorial (int)\n", + " \"\"\"\n", + " if n == 0:\n", + " return 1\n", + " return n * factorial(n - 1)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "6" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "factorial(3)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "3628800" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "factorial(10)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "Note that the [math ](https://docs.python.org/3/library/math.html) module in the [standard library ](https://docs.python.org/3/library/index.html) provides a [factorial() ](https://docs.python.org/3/library/math.html#math.factorial) function as well, and we should, therefore, *never* implement it ourselves in a real codebase." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [], + "source": [ + "import math" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Help on built-in function factorial in module math:\n", + "\n", + "factorial(x, /)\n", + " Find x!.\n", + " \n", + " Raise a ValueError if x is negative or non-integral.\n", + "\n" + ] + } + ], + "source": [ + "help(math.factorial)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "6" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "math.factorial(3)" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "3628800" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "math.factorial(10)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "### \"Involved\" Example: [Euclid's Algorithm ](https://en.wikipedia.org/wiki/Euclidean_algorithm)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "As famous philosopher Euclid already shows in his \"Elements\" (ca. 300 BC), the greatest common divisor of two integers, i.e., the largest number that divides both integers without a remainder, can be efficiently computed with the following code. This example illustrates that a recursive solution to a problem is not always easy to understand." + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "def gcd(a, b):\n", + " \"\"\"Calculate the greatest common divisor of two numbers.\n", + "\n", + " Args:\n", + " a (int): first number\n", + " b (int): second number\n", + "\n", + " Returns:\n", + " gcd (int)\n", + " \"\"\"\n", + " if b == 0:\n", + " return a \n", + " return gcd(b, a % b)" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "4" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "gcd(12, 4)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "Euclid's algorithm is stunningly fast, even for large numbers. Its speed comes from the use of the modulo operator `%`. However, this is *not* true for recursion in general, which may result in slow programs if not applied correctly." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "9" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "gcd(112233445566778899, 987654321)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "As expected, for two [prime numbers ](https://en.wikipedia.org/wiki/List_of_prime_numbers) the greatest common divisor is of course $1$." + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "gcd(7, 7919)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "The [math ](https://docs.python.org/3/library/math.html) module in the [standard library ](https://docs.python.org/3/library/index.html) provides a [gcd() ](https://docs.python.org/3/library/math.html#math.gcd) function as well, and, therefore, we should again *never* implement it on our own." + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Help on built-in function gcd in module math:\n", + "\n", + "gcd(x, y, /)\n", + " greatest common divisor of x and y\n", + "\n" + ] + } + ], + "source": [ + "help(math.gcd)" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "4" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "math.gcd(12, 4)" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "9" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "math.gcd(112233445566778899, 987654321)" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "math.gcd(7, 7919)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "### \"Easy at first Glance\" Example: [Fibonacci Numbers ](https://en.wikipedia.org/wiki/Fibonacci_number)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "The Fibonacci numbers are an infinite sequence of non-negative integers that are calculated such that every number is the sum of its two predecessors where the first two numbers of the sequence are defined to be $0$ and $1$. For example, the first 13 numbers are:" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "$0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144$" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "Let's write a function `fibonacci()` that calculates the $i$th Fibonacci number where $0$ is the $0$th number. Looking at the numbers in a **backward** fashion (i.e., from right to left), we realize that the return value for `fibonacci(i)` can be reduced to the sum of the return values for `fibonacci(i - 1)` and `fibonacci(i - 2)` disregarding the *two* base cases." + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [], + "source": [ + "def fibonacci(i):\n", + " \"\"\"Calculate the ith Fibonacci number.\n", + "\n", + " Args:\n", + " i (int): index of the Fibonacci number to calculate\n", + "\n", + " Returns:\n", + " ith_fibonacci (int)\n", + " \"\"\"\n", + " if i == 0:\n", + " return 0\n", + " elif i == 1:\n", + " return 1\n", + " return fibonacci(i - 1) + fibonacci(i - 2)" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "144" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fibonacci(12) # = 13th number" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "##### Efficiency of Algorithms" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "This implementation is *highly* **inefficient** as small Fibonacci numbers already take a very long time to compute. The reason for this is **exponential growth** in the number of function calls. As [PythonTutor ](http://pythontutor.com/visualize.html#code=def%20fibonacci%28i%29%3A%0A%20%20%20%20if%20i%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%200%0A%20%20%20%20elif%20i%20%3D%3D%201%3A%0A%20%20%20%20%20%20%20%20return%201%0A%20%20%20%20return%20fibonacci%28i%20-%201%29%20%2B%20fibonacci%28i%20-%202%29%0A%0Arv%20%3D%20fibonacci%285%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false) shows, `fibonacci()` is called again and again with the same `i` arguments.\n", + "\n", + "To understand this in detail, we have to study algorithms and data structures (e.g., with [this book](https://www.amazon.de/Introduction-Algorithms-Press-Thomas-Cormen/dp/0262033844/ref=sr_1_1?__mk_de_DE=%C3%85M%C3%85%C5%BD%C3%95%C3%91&crid=1JNE8U0VZGU0O&qid=1569837169&s=gateway&sprefix=algorithms+an%2Caps%2C180&sr=8-1)), a discipline within computer science, and dive into the analysis of **[time complexity of algorithms ](https://en.wikipedia.org/wiki/Time_complexity)**.\n", + "\n", + "Luckily, in the Fibonacci case, the inefficiency can be resolved with a **caching** (i.e., \"reuse\") strategy from the field of **[dynamic programming ](https://en.wikipedia.org/wiki/Dynamic_programming)**, namely **[memoization ](https://en.wikipedia.org/wiki/Memoization)**. We do so in [Chapter 9 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/09_mappings/00_content.ipynb#Memoization), after introducing the `dict` data type.\n", + "\n", + "Let's measure the average run times for `fibonacci()` and varying `i` arguments with the `%%timeit` [cell magic](https://ipython.readthedocs.io/en/stable/interactive/magics.html#magic-timeit) that comes with Jupyter." + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "38.9 µs ± 1.48 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n" + ] + } + ], + "source": [ + "%%timeit -n 100\n", + "fibonacci(12)" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "12.2 ms ± 77.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n" + ] + } + ], + "source": [ + "%%timeit -n 100\n", + "fibonacci(24)" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "3.89 s ± 0 ns per loop (mean ± std. dev. of 1 run, 1 loop each)\n" + ] + } + ], + "source": [ + "%%timeit -n 1 -r 1\n", + "fibonacci(36)" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "6.28 s ± 0 ns per loop (mean ± std. dev. of 1 run, 1 loop each)\n" + ] + } + ], + "source": [ + "%%timeit -n 1 -r 1\n", + "fibonacci(37)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Infinite Recursion" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "If a recursion does not reach its base case, it theoretically runs forever. Luckily, Python detects that and saves the computer from crashing by raising a `RecursionError`.\n", + "\n", + "The simplest possible infinite recursion is generated like so." + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "def run_forever():\n", + " \"\"\"Also a pointless function should have a docstring.\"\"\"\n", + " run_forever()" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "ename": "RecursionError", + "evalue": "maximum recursion depth exceeded", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mRecursionError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mrun_forever\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;36mrun_forever\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mrun_forever\u001b[0m\u001b[0;34m(\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[1;32m 2\u001b[0m \u001b[0;34m\"\"\"Also a pointless function should have a docstring.\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0mrun_forever\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", + "... last 1 frames repeated, from the frame below ...\n", + "\u001b[0;32m\u001b[0m in \u001b[0;36mrun_forever\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mrun_forever\u001b[0m\u001b[0;34m(\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[1;32m 2\u001b[0m \u001b[0;34m\"\"\"Also a pointless function should have a docstring.\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0mrun_forever\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;31mRecursionError\u001b[0m: maximum recursion depth exceeded" + ] + } + ], + "source": [ + "run_forever()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "However, even the trivial `countdown()` function from above is not immune to infinite recursion. Let's call it with `3.1` instead of `3`. What goes wrong here?" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "3.1\n", + "2.1\n", + "1.1\n", + "0.10000000000000009\n", + "-0.8999999999999999\n", + "-1.9\n", + "-2.9\n", + "-3.9\n", + "-4.9\n", + "-5.9\n", + "-6.9\n", + "-7.9\n", + "-8.9\n", + "-9.9\n", + "-10.9\n", + "-11.9\n", + "-12.9\n", + "-13.9\n", + "-14.9\n", + "-15.9\n", + "-16.9\n", + "-17.9\n", + "-18.9\n", + "-19.9\n", + "-20.9\n", + "-21.9\n", + "-22.9\n", + "-23.9\n", + "-24.9\n", + "-25.9\n", + "-26.9\n", + "-27.9\n", + "-28.9\n", + "-29.9\n", + "-30.9\n", + "-31.9\n", + "-32.9\n", + "-33.9\n", + "-34.9\n", + "-35.9\n", + "-36.9\n", + "-37.9\n", + "-38.9\n", + "-39.9\n", + "-40.9\n", + "-41.9\n", + "-42.9\n", + "-43.9\n", + "-44.9\n", + "-45.9\n", + "-46.9\n", + "-47.9\n", + "-48.9\n", + "-49.9\n", + "-50.9\n", + "-51.9\n", + "-52.9\n", + "-53.9\n", + "-54.9\n", + "-55.9\n", + "-56.9\n", + "-57.9\n", + "-58.9\n", + "-59.9\n", + "-60.9\n", + "-61.9\n", + "-62.9\n", + "-63.9\n", + "-64.9\n", + "-65.9\n", + "-66.9\n", + "-67.9\n", + "-68.9\n", + "-69.9\n", + "-70.9\n", + "-71.9\n", + "-72.9\n", + "-73.9\n", + "-74.9\n", + "-75.9\n", + "-76.9\n", + "-77.9\n", + "-78.9\n", + "-79.9\n", + "-80.9\n", + "-81.9\n", + "-82.9\n", + "-83.9\n", + "-84.9\n", + "-85.9\n", + "-86.9\n", + "-87.9\n", + "-88.9\n", + "-89.9\n", + "-90.9\n", + "-91.9\n", + "-92.9\n", + "-93.9\n", + "-94.9\n", + "-95.9\n", + "-96.9\n", + "-97.9\n", + "-98.9\n", + "-99.9\n", + "-100.9\n", + "-101.9\n", + "-102.9\n", + "-103.9\n", + "-104.9\n", + "-105.9\n", + "-106.9\n", + "-107.9\n", + "-108.9\n", + "-109.9\n", + "-110.9\n", + "-111.9\n", + "-112.9\n", + "-113.9\n", + "-114.9\n", + "-115.9\n", + "-116.9\n", + "-117.9\n", + "-118.9\n", + "-119.9\n", + "-120.9\n", + "-121.9\n", + "-122.9\n", + "-123.9\n", + "-124.9\n", + "-125.9\n", + "-126.9\n", + "-127.9\n", + "-128.9\n", + "-129.9\n", + "-130.9\n", + "-131.9\n", + "-132.9\n", + "-133.9\n", + "-134.9\n", + "-135.9\n", + "-136.9\n", + "-137.9\n", + "-138.9\n", + "-139.9\n", + "-140.9\n", + "-141.9\n", + "-142.9\n", + "-143.9\n", + "-144.9\n", + "-145.9\n", + "-146.9\n", + "-147.9\n", + "-148.9\n", + "-149.9\n", + "-150.9\n", + "-151.9\n", + "-152.9\n", + "-153.9\n", + "-154.9\n", + "-155.9\n", + "-156.9\n", + "-157.9\n", + "-158.9\n", + "-159.9\n", + "-160.9\n", + "-161.9\n", + "-162.9\n", + "-163.9\n", + "-164.9\n", + "-165.9\n", + "-166.9\n", + "-167.9\n", + "-168.9\n", + "-169.9\n", + "-170.9\n", + "-171.9\n", + "-172.9\n", + "-173.9\n", + "-174.9\n", + "-175.9\n", + "-176.9\n", + "-177.9\n", + "-178.9\n", + "-179.9\n", + "-180.9\n", + "-181.9\n", + "-182.9\n", + "-183.9\n", + "-184.9\n", + "-185.9\n", + "-186.9\n", + "-187.9\n", + "-188.9\n", + "-189.9\n", + "-190.9\n", + "-191.9\n", + "-192.9\n", + "-193.9\n", + "-194.9\n", + "-195.9\n", + "-196.9\n", + "-197.9\n", + "-198.9\n", + "-199.9\n", + "-200.9\n", + "-201.9\n", + "-202.9\n", + "-203.9\n", + "-204.9\n", + "-205.9\n", + "-206.9\n", + "-207.9\n", + "-208.9\n", + "-209.9\n", + "-210.9\n", + "-211.9\n", + "-212.9\n", + "-213.9\n", + "-214.9\n", + "-215.9\n", + "-216.9\n", + "-217.9\n", + "-218.9\n", + "-219.9\n", + "-220.9\n", + "-221.9\n", + "-222.9\n", + "-223.9\n", + "-224.9\n", + "-225.9\n", + "-226.9\n", + "-227.9\n", + "-228.9\n", + "-229.9\n", + "-230.9\n", + "-231.9\n", + "-232.9\n", + "-233.9\n", + "-234.9\n", + "-235.9\n", + "-236.9\n", + "-237.9\n", + "-238.9\n", + "-239.9\n", + "-240.9\n", + "-241.9\n", + "-242.9\n", + "-243.9\n", + "-244.9\n", + "-245.9\n", + "-246.9\n", + "-247.9\n", + "-248.9\n", + "-249.9\n", + "-250.9\n", + "-251.9\n", + "-252.9\n", + "-253.9\n", + "-254.9\n", + "-255.9\n", + "-256.9\n", + "-257.9\n", + "-258.9\n", + "-259.9\n", + "-260.9\n", + "-261.9\n", + "-262.9\n", + "-263.9\n", + "-264.9\n", + "-265.9\n", + "-266.9\n", + "-267.9\n", + "-268.9\n", + "-269.9\n", + "-270.9\n", + "-271.9\n", + "-272.9\n", + "-273.9\n", + "-274.9\n", + "-275.9\n", + "-276.9\n", + "-277.9\n", + "-278.9\n", + "-279.9\n", + "-280.9\n", + "-281.9\n", + "-282.9\n", + "-283.9\n", + "-284.9\n", + "-285.9\n", + "-286.9\n", + "-287.9\n", + "-288.9\n", + "-289.9\n", + "-290.9\n", + "-291.9\n", + "-292.9\n", + "-293.9\n", + "-294.9\n", + "-295.9\n", + "-296.9\n", + "-297.9\n", + "-298.9\n", + "-299.9\n", + "-300.9\n", + "-301.9\n", + "-302.9\n", + "-303.9\n", + "-304.9\n", + "-305.9\n", + "-306.9\n", + "-307.9\n", + "-308.9\n", + "-309.9\n", + "-310.9\n", + "-311.9\n", + "-312.9\n", + "-313.9\n", + "-314.9\n", + "-315.9\n", + "-316.9\n", + "-317.9\n", + "-318.9\n", + "-319.9\n", + "-320.9\n", + "-321.9\n", + "-322.9\n", + "-323.9\n", + "-324.9\n", + "-325.9\n", + "-326.9\n", + "-327.9\n", + "-328.9\n", + "-329.9\n", + "-330.9\n", + "-331.9\n", + "-332.9\n", + "-333.9\n", + "-334.9\n", + "-335.9\n", + "-336.9\n", + "-337.9\n", + "-338.9\n", + "-339.9\n", + "-340.9\n", + "-341.9\n", + "-342.9\n", + "-343.9\n", + "-344.9\n", + "-345.9\n", + "-346.9\n", + "-347.9\n", + "-348.9\n", + "-349.9\n", + "-350.9\n", + "-351.9\n", + "-352.9\n", + "-353.9\n", + "-354.9\n", + "-355.9\n", + "-356.9\n", + "-357.9\n", + "-358.9\n", + "-359.9\n", + "-360.9\n", + "-361.9\n", + "-362.9\n", + "-363.9\n", + "-364.9\n", + "-365.9\n", + "-366.9\n", + "-367.9\n", + "-368.9\n", + "-369.9\n", + "-370.9\n", + "-371.9\n", + "-372.9\n", + "-373.9\n", + "-374.9\n", + "-375.9\n", + "-376.9\n", + "-377.9\n", + "-378.9\n", + "-379.9\n", + "-380.9\n", + "-381.9\n", + "-382.9\n", + "-383.9\n", + "-384.9\n", + "-385.9\n", + "-386.9\n", + "-387.9\n", + "-388.9\n", + "-389.9\n", + "-390.9\n", + "-391.9\n", + "-392.9\n", + "-393.9\n", + "-394.9\n", + "-395.9\n", + "-396.9\n", + "-397.9\n", + "-398.9\n", + "-399.9\n", + "-400.9\n", + "-401.9\n", + "-402.9\n", + "-403.9\n", + "-404.9\n", + "-405.9\n", + "-406.9\n", + "-407.9\n", + "-408.9\n", + "-409.9\n", + "-410.9\n", + "-411.9\n", + "-412.9\n", + "-413.9\n", + "-414.9\n", + "-415.9\n", + "-416.9\n", + "-417.9\n", + "-418.9\n", + "-419.9\n", + "-420.9\n", + "-421.9\n", + "-422.9\n", + "-423.9\n", + "-424.9\n", + "-425.9\n", + "-426.9\n", + "-427.9\n", + "-428.9\n", + "-429.9\n", + "-430.9\n", + "-431.9\n", + "-432.9\n", + "-433.9\n", + "-434.9\n", + "-435.9\n", + "-436.9\n", + "-437.9\n", + "-438.9\n", + "-439.9\n", + "-440.9\n", + "-441.9\n", + "-442.9\n", + "-443.9\n", + "-444.9\n", + "-445.9\n", + "-446.9\n", + "-447.9\n", + "-448.9\n", + "-449.9\n", + "-450.9\n", + "-451.9\n", + "-452.9\n", + "-453.9\n", + "-454.9\n", + "-455.9\n", + "-456.9\n", + "-457.9\n", + "-458.9\n", + "-459.9\n", + "-460.9\n", + "-461.9\n", + "-462.9\n", + "-463.9\n", + "-464.9\n", + "-465.9\n", + "-466.9\n", + "-467.9\n", + "-468.9\n", + "-469.9\n", + "-470.9\n", + "-471.9\n", + "-472.9\n", + "-473.9\n", + "-474.9\n", + "-475.9\n", + "-476.9\n", + "-477.9\n", + "-478.9\n", + "-479.9\n", + "-480.9\n", + "-481.9\n", + "-482.9\n", + "-483.9\n", + "-484.9\n", + "-485.9\n", + "-486.9\n", + "-487.9\n", + "-488.9\n", + "-489.9\n", + "-490.9\n", + "-491.9\n", + "-492.9\n", + "-493.9\n", + "-494.9\n", + "-495.9\n", + "-496.9\n", + "-497.9\n", + "-498.9\n", + "-499.9\n", + "-500.9\n", + "-501.9\n", + "-502.9\n", + "-503.9\n", + "-504.9\n", + "-505.9\n", + "-506.9\n", + "-507.9\n", + "-508.9\n", + "-509.9\n", + "-510.9\n", + "-511.9\n", + "-512.9\n", + "-513.9\n", + "-514.9\n", + "-515.9\n", + "-516.9\n", + "-517.9\n", + "-518.9\n", + "-519.9\n", + "-520.9\n", + "-521.9\n", + "-522.9\n", + "-523.9\n", + "-524.9\n", + "-525.9\n", + "-526.9\n", + "-527.9\n", + "-528.9\n", + "-529.9\n", + "-530.9\n", + "-531.9\n", + "-532.9\n", + "-533.9\n", + "-534.9\n", + "-535.9\n", + "-536.9\n", + "-537.9\n", + "-538.9\n", + "-539.9\n", + "-540.9\n", + "-541.9\n", + "-542.9\n", + "-543.9\n", + "-544.9\n", + "-545.9\n", + "-546.9\n", + "-547.9\n", + "-548.9\n", + "-549.9\n", + "-550.9\n", + "-551.9\n", + "-552.9\n", + "-553.9\n", + "-554.9\n", + "-555.9\n", + "-556.9\n", + "-557.9\n", + "-558.9\n", + "-559.9\n", + "-560.9\n", + "-561.9\n", + "-562.9\n", + "-563.9\n", + "-564.9\n", + "-565.9\n", + "-566.9\n", + "-567.9\n", + "-568.9\n", + "-569.9\n", + "-570.9\n", + "-571.9\n", + "-572.9\n", + "-573.9\n", + "-574.9\n", + "-575.9\n", + "-576.9\n", + "-577.9\n", + "-578.9\n", + "-579.9\n", + "-580.9\n", + "-581.9\n", + "-582.9\n", + "-583.9\n", + "-584.9\n", + "-585.9\n", + "-586.9\n", + "-587.9\n", + "-588.9\n", + "-589.9\n", + "-590.9\n", + "-591.9\n", + "-592.9\n", + "-593.9\n", + "-594.9\n", + "-595.9\n", + "-596.9\n", + "-597.9\n", + "-598.9\n", + "-599.9\n", + "-600.9\n", + "-601.9\n", + "-602.9\n", + "-603.9\n", + "-604.9\n", + "-605.9\n", + "-606.9\n", + "-607.9\n", + "-608.9\n", + "-609.9\n", + "-610.9\n", + "-611.9\n", + "-612.9\n", + "-613.9\n", + "-614.9\n", + "-615.9\n", + "-616.9\n", + "-617.9\n", + "-618.9\n", + "-619.9\n", + "-620.9\n", + "-621.9\n", + "-622.9\n", + "-623.9\n", + "-624.9\n", + "-625.9\n", + "-626.9\n", + "-627.9\n", + "-628.9\n", + "-629.9\n", + "-630.9\n", + "-631.9\n", + "-632.9\n", + "-633.9\n", + "-634.9\n", + "-635.9\n", + "-636.9\n", + "-637.9\n", + "-638.9\n", + "-639.9\n", + "-640.9\n", + "-641.9\n", + "-642.9\n", + "-643.9\n", + "-644.9\n", + "-645.9\n", + "-646.9\n", + "-647.9\n", + "-648.9\n", + "-649.9\n", + "-650.9\n", + "-651.9\n", + "-652.9\n", + "-653.9\n", + "-654.9\n", + "-655.9\n", + "-656.9\n", + "-657.9\n", + "-658.9\n", + "-659.9\n", + "-660.9\n", + "-661.9\n", + "-662.9\n", + "-663.9\n", + "-664.9\n", + "-665.9\n", + "-666.9\n", + "-667.9\n", + "-668.9\n", + "-669.9\n", + "-670.9\n", + "-671.9\n", + "-672.9\n", + "-673.9\n", + "-674.9\n", + "-675.9\n", + "-676.9\n", + "-677.9\n", + "-678.9\n", + "-679.9\n", + "-680.9\n", + "-681.9\n", + "-682.9\n", + "-683.9\n", + "-684.9\n", + "-685.9\n", + "-686.9\n", + "-687.9\n", + "-688.9\n", + "-689.9\n", + "-690.9\n", + "-691.9\n", + "-692.9\n", + "-693.9\n", + "-694.9\n", + "-695.9\n", + "-696.9\n", + "-697.9\n", + "-698.9\n", + "-699.9\n", + "-700.9\n", + "-701.9\n", + "-702.9\n", + "-703.9\n", + "-704.9\n", + "-705.9\n", + "-706.9\n", + "-707.9\n", + "-708.9\n", + "-709.9\n", + "-710.9\n", + "-711.9\n", + "-712.9\n", + "-713.9\n", + "-714.9\n", + "-715.9\n", + "-716.9\n", + "-717.9\n", + "-718.9\n", + "-719.9\n", + "-720.9\n", + "-721.9\n", + "-722.9\n", + "-723.9\n", + "-724.9\n", + "-725.9\n", + "-726.9\n", + "-727.9\n", + "-728.9\n", + "-729.9\n", + "-730.9\n", + "-731.9\n", + "-732.9\n", + "-733.9\n", + "-734.9\n", + "-735.9\n", + "-736.9\n", + "-737.9\n", + "-738.9\n", + "-739.9\n", + "-740.9\n", + "-741.9\n", + "-742.9\n", + "-743.9\n", + "-744.9\n", + "-745.9\n", + "-746.9\n", + "-747.9\n", + "-748.9\n", + "-749.9\n", + "-750.9\n", + "-751.9\n", + "-752.9\n", + "-753.9\n", + "-754.9\n", + "-755.9\n", + "-756.9\n", + "-757.9\n", + "-758.9\n", + "-759.9\n", + "-760.9\n", + "-761.9\n", + "-762.9\n", + "-763.9\n", + "-764.9\n", + "-765.9\n", + "-766.9\n", + "-767.9\n", + "-768.9\n", + "-769.9\n", + "-770.9\n", + "-771.9\n", + "-772.9\n", + "-773.9\n", + "-774.9\n", + "-775.9\n", + "-776.9\n", + "-777.9\n", + "-778.9\n", + "-779.9\n", + "-780.9\n", + "-781.9\n", + "-782.9\n", + "-783.9\n", + "-784.9\n", + "-785.9\n", + "-786.9\n", + "-787.9\n", + "-788.9\n", + "-789.9\n", + "-790.9\n", + "-791.9\n", + "-792.9\n", + "-793.9\n", + "-794.9\n", + "-795.9\n", + "-796.9\n", + "-797.9\n", + "-798.9\n", + "-799.9\n", + "-800.9\n", + "-801.9\n", + "-802.9\n", + "-803.9\n", + "-804.9\n", + "-805.9\n", + "-806.9\n", + "-807.9\n", + "-808.9\n", + "-809.9\n", + "-810.9\n", + "-811.9\n", + "-812.9\n", + "-813.9\n", + "-814.9\n", + "-815.9\n", + "-816.9\n", + "-817.9\n", + "-818.9\n", + "-819.9\n", + "-820.9\n", + "-821.9\n", + "-822.9\n", + "-823.9\n", + "-824.9\n", + "-825.9\n", + "-826.9\n", + "-827.9\n", + "-828.9\n", + "-829.9\n", + "-830.9\n", + "-831.9\n", + "-832.9\n", + "-833.9\n", + "-834.9\n", + "-835.9\n", + "-836.9\n", + "-837.9\n", + "-838.9\n", + "-839.9\n", + "-840.9\n", + "-841.9\n", + "-842.9\n", + "-843.9\n", + "-844.9\n", + "-845.9\n", + "-846.9\n", + "-847.9\n", + "-848.9\n", + "-849.9\n", + "-850.9\n", + "-851.9\n", + "-852.9\n", + "-853.9\n", + "-854.9\n", + "-855.9\n", + "-856.9\n", + "-857.9\n", + "-858.9\n", + "-859.9\n", + "-860.9\n", + "-861.9\n", + "-862.9\n", + "-863.9\n", + "-864.9\n", + "-865.9\n", + "-866.9\n", + "-867.9\n", + "-868.9\n", + "-869.9\n", + "-870.9\n", + "-871.9\n", + "-872.9\n", + "-873.9\n", + "-874.9\n", + "-875.9\n", + "-876.9\n", + "-877.9\n", + "-878.9\n", + "-879.9\n", + "-880.9\n", + "-881.9\n", + "-882.9\n", + "-883.9\n", + "-884.9\n", + "-885.9\n", + "-886.9\n", + "-887.9\n", + "-888.9\n", + "-889.9\n", + "-890.9\n", + "-891.9\n", + "-892.9\n", + "-893.9\n", + "-894.9\n", + "-895.9\n", + "-896.9\n", + "-897.9\n", + "-898.9\n", + "-899.9\n", + "-900.9\n", + "-901.9\n", + "-902.9\n", + "-903.9\n", + "-904.9\n", + "-905.9\n", + "-906.9\n", + "-907.9\n", + "-908.9\n", + "-909.9\n", + "-910.9\n", + "-911.9\n", + "-912.9\n", + "-913.9\n", + "-914.9\n", + "-915.9\n", + "-916.9\n", + "-917.9\n", + "-918.9\n", + "-919.9\n", + "-920.9\n", + "-921.9\n", + "-922.9\n", + "-923.9\n", + "-924.9\n", + "-925.9\n", + "-926.9\n", + "-927.9\n", + "-928.9\n", + "-929.9\n", + "-930.9\n", + "-931.9\n", + "-932.9\n", + "-933.9\n", + "-934.9\n", + "-935.9\n", + "-936.9\n", + "-937.9\n", + "-938.9\n", + "-939.9\n", + "-940.9\n", + "-941.9\n", + "-942.9\n", + "-943.9\n", + "-944.9\n", + "-945.9\n", + "-946.9\n", + "-947.9\n", + "-948.9\n", + "-949.9\n", + "-950.9\n", + "-951.9\n", + "-952.9\n", + "-953.9\n", + "-954.9\n", + "-955.9\n", + "-956.9\n", + "-957.9\n", + "-958.9\n", + "-959.9\n", + "-960.9\n", + "-961.9\n", + "-962.9\n", + "-963.9\n", + "-964.9\n", + "-965.9\n", + "-966.9\n", + "-967.9\n", + "-968.9\n", + "-969.9\n", + "-970.9\n", + "-971.9\n", + "-972.9\n", + "-973.9\n", + "-974.9\n", + "-975.9\n", + "-976.9\n", + "-977.9\n", + "-978.9\n", + "-979.9\n", + "-980.9\n", + "-981.9\n", + "-982.9\n", + "-983.9\n", + "-984.9\n", + "-985.9\n", + "-986.9\n", + "-987.9\n", + "-988.9\n", + "-989.9\n", + "-990.9\n", + "-991.9\n", + "-992.9\n", + "-993.9\n", + "-994.9\n", + "-995.9\n", + "-996.9\n", + "-997.9\n", + "-998.9\n", + "-999.9\n", + "-1000.9\n", + "-1001.9\n", + "-1002.9\n", + "-1003.9\n", + "-1004.9\n", + "-1005.9\n", + "-1006.9\n", + "-1007.9\n", + "-1008.9\n", + "-1009.9\n", + "-1010.9\n", + "-1011.9\n", + "-1012.9\n", + "-1013.9\n", + "-1014.9\n", + "-1015.9\n", + "-1016.9\n", + "-1017.9\n", + "-1018.9\n", + "-1019.9\n", + "-1020.9\n", + "-1021.9\n", + "-1022.9\n", + "-1023.9\n", + "-1024.9\n", + "-1025.9\n", + "-1026.9\n", + "-1027.9\n", + "-1028.9\n", + "-1029.9\n", + "-1030.9\n", + "-1031.9\n", + "-1032.9\n", + "-1033.9\n", + "-1034.9\n", + "-1035.9\n", + "-1036.9\n", + "-1037.9\n", + "-1038.9\n", + "-1039.9\n", + "-1040.9\n", + "-1041.9\n", + "-1042.9\n", + "-1043.9\n", + "-1044.9\n", + "-1045.9\n", + "-1046.9\n", + "-1047.9\n", + "-1048.9\n", + "-1049.9\n", + "-1050.9\n", + "-1051.9\n", + "-1052.9\n", + "-1053.9\n", + "-1054.9\n", + "-1055.9\n", + "-1056.9\n", + "-1057.9\n", + "-1058.9\n", + "-1059.9\n", + "-1060.9\n", + "-1061.9\n", + "-1062.9\n", + "-1063.9\n", + "-1064.9\n", + "-1065.9\n", + "-1066.9\n", + "-1067.9\n", + "-1068.9\n", + "-1069.9\n", + "-1070.9\n", + "-1071.9\n", + "-1072.9\n", + "-1073.9\n", + "-1074.9\n", + "-1075.9\n", + "-1076.9\n", + "-1077.9\n", + "-1078.9\n", + "-1079.9\n", + "-1080.9\n", + "-1081.9\n", + "-1082.9\n", + "-1083.9\n", + "-1084.9\n", + "-1085.9\n", + "-1086.9\n", + "-1087.9\n", + "-1088.9\n", + "-1089.9\n", + "-1090.9\n", + "-1091.9\n", + "-1092.9\n", + "-1093.9\n", + "-1094.9\n", + "-1095.9\n", + "-1096.9\n", + "-1097.9\n", + "-1098.9\n", + "-1099.9\n", + "-1100.9\n", + "-1101.9\n", + "-1102.9\n", + "-1103.9\n", + "-1104.9\n", + "-1105.9\n", + "-1106.9\n", + "-1107.9\n", + "-1108.9\n", + "-1109.9\n", + "-1110.9\n", + "-1111.9\n", + "-1112.9\n", + "-1113.9\n", + "-1114.9\n", + "-1115.9\n", + "-1116.9\n", + "-1117.9\n", + "-1118.9\n", + "-1119.9\n", + "-1120.9\n", + "-1121.9\n", + "-1122.9\n", + "-1123.9\n", + "-1124.9\n", + "-1125.9\n", + "-1126.9\n", + "-1127.9\n", + "-1128.9\n", + "-1129.9\n", + "-1130.9\n", + "-1131.9\n", + "-1132.9\n", + "-1133.9\n", + "-1134.9\n", + "-1135.9\n", + "-1136.9\n", + "-1137.9\n", + "-1138.9\n", + "-1139.9\n", + "-1140.9\n", + "-1141.9\n", + "-1142.9\n", + "-1143.9\n", + "-1144.9\n", + "-1145.9\n", + "-1146.9\n", + "-1147.9\n", + "-1148.9\n", + "-1149.9\n", + "-1150.9\n", + "-1151.9\n", + "-1152.9\n", + "-1153.9\n", + "-1154.9\n", + "-1155.9\n", + "-1156.9\n", + "-1157.9\n", + "-1158.9\n", + "-1159.9\n", + "-1160.9\n", + "-1161.9\n", + "-1162.9\n", + "-1163.9\n", + "-1164.9\n", + "-1165.9\n", + "-1166.9\n", + "-1167.9\n", + "-1168.9\n", + "-1169.9\n", + "-1170.9\n", + "-1171.9\n", + "-1172.9\n", + "-1173.9\n", + "-1174.9\n", + "-1175.9\n", + "-1176.9\n", + "-1177.9\n", + "-1178.9\n", + "-1179.9\n", + "-1180.9\n", + "-1181.9\n", + "-1182.9\n", + "-1183.9\n", + "-1184.9\n", + "-1185.9\n", + "-1186.9\n", + "-1187.9\n", + "-1188.9\n", + "-1189.9\n", + "-1190.9\n", + "-1191.9\n", + "-1192.9\n", + "-1193.9\n", + "-1194.9\n", + "-1195.9\n", + "-1196.9\n", + "-1197.9\n", + "-1198.9\n", + "-1199.9\n", + "-1200.9\n", + "-1201.9\n", + "-1202.9\n", + "-1203.9\n", + "-1204.9\n", + "-1205.9\n", + "-1206.9\n", + "-1207.9\n", + "-1208.9\n", + "-1209.9\n", + "-1210.9\n", + "-1211.9\n", + "-1212.9\n", + "-1213.9\n", + "-1214.9\n", + "-1215.9\n", + "-1216.9\n", + "-1217.9\n", + "-1218.9\n", + "-1219.9\n", + "-1220.9\n", + "-1221.9\n", + "-1222.9\n", + "-1223.9\n", + "-1224.9\n", + "-1225.9\n", + "-1226.9\n", + "-1227.9\n", + "-1228.9\n", + "-1229.9\n", + "-1230.9\n", + "-1231.9\n", + "-1232.9\n", + "-1233.9\n", + "-1234.9\n", + "-1235.9\n", + "-1236.9\n", + "-1237.9\n", + "-1238.9\n", + "-1239.9\n", + "-1240.9\n", + "-1241.9\n", + "-1242.9\n", + "-1243.9\n", + "-1244.9\n", + "-1245.9\n", + "-1246.9\n", + "-1247.9\n", + "-1248.9\n", + "-1249.9\n", + "-1250.9\n", + "-1251.9\n", + "-1252.9\n", + "-1253.9\n", + "-1254.9\n", + "-1255.9\n", + "-1256.9\n", + "-1257.9\n", + "-1258.9\n", + "-1259.9\n", + "-1260.9\n", + "-1261.9\n", + "-1262.9\n", + "-1263.9\n", + "-1264.9\n", + "-1265.9\n", + "-1266.9\n", + "-1267.9\n", + "-1268.9\n", + "-1269.9\n", + "-1270.9\n", + "-1271.9\n", + "-1272.9\n", + "-1273.9\n", + "-1274.9\n", + "-1275.9\n", + "-1276.9\n", + "-1277.9\n", + "-1278.9\n", + "-1279.9\n", + "-1280.9\n", + "-1281.9\n", + "-1282.9\n", + "-1283.9\n", + "-1284.9\n", + "-1285.9\n", + "-1286.9\n", + "-1287.9\n", + "-1288.9\n", + "-1289.9\n", + "-1290.9\n", + "-1291.9\n", + "-1292.9\n", + "-1293.9\n", + "-1294.9\n", + "-1295.9\n", + "-1296.9\n", + "-1297.9\n", + "-1298.9\n", + "-1299.9\n", + "-1300.9\n", + "-1301.9\n", + "-1302.9\n", + "-1303.9\n", + "-1304.9\n", + "-1305.9\n", + "-1306.9\n", + "-1307.9\n", + "-1308.9\n", + "-1309.9\n", + "-1310.9\n", + "-1311.9\n", + "-1312.9\n", + "-1313.9\n", + "-1314.9\n", + "-1315.9\n", + "-1316.9\n", + "-1317.9\n", + "-1318.9\n", + "-1319.9\n", + "-1320.9\n", + "-1321.9\n", + "-1322.9\n", + "-1323.9\n", + "-1324.9\n", + "-1325.9\n", + "-1326.9\n", + "-1327.9\n", + "-1328.9\n", + "-1329.9\n", + "-1330.9\n", + "-1331.9\n", + "-1332.9\n", + "-1333.9\n", + "-1334.9\n", + "-1335.9\n", + "-1336.9\n", + "-1337.9\n", + "-1338.9\n", + "-1339.9\n", + "-1340.9\n", + "-1341.9\n", + "-1342.9\n", + "-1343.9\n", + "-1344.9\n", + "-1345.9\n", + "-1346.9\n", + "-1347.9\n", + "-1348.9\n", + "-1349.9\n", + "-1350.9\n", + "-1351.9\n", + "-1352.9\n", + "-1353.9\n", + "-1354.9\n", + "-1355.9\n", + "-1356.9\n", + "-1357.9\n", + "-1358.9\n", + "-1359.9\n", + "-1360.9\n", + "-1361.9\n", + "-1362.9\n", + "-1363.9\n", + "-1364.9\n", + "-1365.9\n", + "-1366.9\n", + "-1367.9\n", + "-1368.9\n", + "-1369.9\n", + "-1370.9\n", + "-1371.9\n", + "-1372.9\n", + "-1373.9\n", + "-1374.9\n", + "-1375.9\n", + "-1376.9\n", + "-1377.9\n", + "-1378.9\n", + "-1379.9\n", + "-1380.9\n", + "-1381.9\n", + "-1382.9\n", + "-1383.9\n", + "-1384.9\n", + "-1385.9\n", + "-1386.9\n", + "-1387.9\n", + "-1388.9\n", + "-1389.9\n", + "-1390.9\n", + "-1391.9\n", + "-1392.9\n", + "-1393.9\n", + "-1394.9\n", + "-1395.9\n", + "-1396.9\n", + "-1397.9\n", + "-1398.9\n", + "-1399.9\n", + "-1400.9\n", + "-1401.9\n", + "-1402.9\n", + "-1403.9\n", + "-1404.9\n", + "-1405.9\n", + "-1406.9\n", + "-1407.9\n", + "-1408.9\n", + "-1409.9\n", + "-1410.9\n", + "-1411.9\n", + "-1412.9\n", + "-1413.9\n", + "-1414.9\n", + "-1415.9\n", + "-1416.9\n", + "-1417.9\n", + "-1418.9\n", + "-1419.9\n", + "-1420.9\n", + "-1421.9\n", + "-1422.9\n", + "-1423.9\n", + "-1424.9\n", + "-1425.9\n", + "-1426.9\n", + "-1427.9\n", + "-1428.9\n", + "-1429.9\n", + "-1430.9\n", + "-1431.9\n", + "-1432.9\n", + "-1433.9\n", + "-1434.9\n", + "-1435.9\n", + "-1436.9\n", + "-1437.9\n", + "-1438.9\n", + "-1439.9\n", + "-1440.9\n", + "-1441.9\n", + "-1442.9\n", + "-1443.9\n", + "-1444.9\n", + "-1445.9\n", + "-1446.9\n", + "-1447.9\n", + "-1448.9\n", + "-1449.9\n", + "-1450.9\n", + "-1451.9\n", + "-1452.9\n", + "-1453.9\n", + "-1454.9\n", + "-1455.9\n", + "-1456.9\n", + "-1457.9\n", + "-1458.9\n", + "-1459.9\n", + "-1460.9\n", + "-1461.9\n", + "-1462.9\n", + "-1463.9\n", + "-1464.9\n", + "-1465.9\n", + "-1466.9\n", + "-1467.9\n", + "-1468.9\n", + "-1469.9\n", + "-1470.9\n", + "-1471.9\n", + "-1472.9\n", + "-1473.9\n", + "-1474.9\n", + "-1475.9\n", + "-1476.9\n", + "-1477.9\n", + "-1478.9\n", + "-1479.9\n", + "-1480.9\n", + "-1481.9\n", + "-1482.9\n", + "-1483.9\n", + "-1484.9\n", + "-1485.9\n", + "-1486.9\n", + "-1487.9\n", + "-1488.9\n", + "-1489.9\n", + "-1490.9\n", + "-1491.9\n", + "-1492.9\n", + "-1493.9\n", + "-1494.9\n", + "-1495.9\n", + "-1496.9\n", + "-1497.9\n", + "-1498.9\n", + "-1499.9\n", + "-1500.9\n", + "-1501.9\n", + "-1502.9\n", + "-1503.9\n", + "-1504.9\n", + "-1505.9\n", + "-1506.9\n", + "-1507.9\n", + "-1508.9\n", + "-1509.9\n", + "-1510.9\n", + "-1511.9\n", + "-1512.9\n", + "-1513.9\n", + "-1514.9\n", + "-1515.9\n", + "-1516.9\n", + "-1517.9\n", + "-1518.9\n", + "-1519.9\n", + "-1520.9\n", + "-1521.9\n", + "-1522.9\n", + "-1523.9\n", + "-1524.9\n", + "-1525.9\n", + "-1526.9\n", + "-1527.9\n", + "-1528.9\n", + "-1529.9\n", + "-1530.9\n", + "-1531.9\n", + "-1532.9\n", + "-1533.9\n", + "-1534.9\n", + "-1535.9\n", + "-1536.9\n", + "-1537.9\n", + "-1538.9\n", + "-1539.9\n", + "-1540.9\n", + "-1541.9\n", + "-1542.9\n", + "-1543.9\n", + "-1544.9\n", + "-1545.9\n", + "-1546.9\n", + "-1547.9\n", + "-1548.9\n", + "-1549.9\n", + "-1550.9\n", + "-1551.9\n", + "-1552.9\n", + "-1553.9\n", + "-1554.9\n", + "-1555.9\n", + "-1556.9\n", + "-1557.9\n", + "-1558.9\n", + "-1559.9\n", + "-1560.9\n", + "-1561.9\n", + "-1562.9\n", + "-1563.9\n", + "-1564.9\n", + "-1565.9\n", + "-1566.9\n", + "-1567.9\n", + "-1568.9\n", + "-1569.9\n", + "-1570.9\n", + "-1571.9\n", + "-1572.9\n", + "-1573.9\n", + "-1574.9\n", + "-1575.9\n", + "-1576.9\n", + "-1577.9\n", + "-1578.9\n", + "-1579.9\n", + "-1580.9\n", + "-1581.9\n", + "-1582.9\n", + "-1583.9\n", + "-1584.9\n", + "-1585.9\n", + "-1586.9\n", + "-1587.9\n", + "-1588.9\n", + "-1589.9\n", + "-1590.9\n", + "-1591.9\n", + "-1592.9\n", + "-1593.9\n", + "-1594.9\n", + "-1595.9\n", + "-1596.9\n", + "-1597.9\n", + "-1598.9\n", + "-1599.9\n", + "-1600.9\n", + "-1601.9\n", + "-1602.9\n", + "-1603.9\n", + "-1604.9\n", + "-1605.9\n", + "-1606.9\n", + "-1607.9\n", + "-1608.9\n", + "-1609.9\n", + "-1610.9\n", + "-1611.9\n", + "-1612.9\n", + "-1613.9\n", + "-1614.9\n", + "-1615.9\n", + "-1616.9\n", + "-1617.9\n", + "-1618.9\n", + "-1619.9\n", + "-1620.9\n", + "-1621.9\n", + "-1622.9\n", + "-1623.9\n", + "-1624.9\n", + "-1625.9\n", + "-1626.9\n", + "-1627.9\n", + "-1628.9\n", + "-1629.9\n", + "-1630.9\n", + "-1631.9\n", + "-1632.9\n", + "-1633.9\n", + "-1634.9\n", + "-1635.9\n", + "-1636.9\n", + "-1637.9\n", + "-1638.9\n", + "-1639.9\n", + "-1640.9\n", + "-1641.9\n", + "-1642.9\n", + "-1643.9\n", + "-1644.9\n", + "-1645.9\n", + "-1646.9\n", + "-1647.9\n", + "-1648.9\n", + "-1649.9\n", + "-1650.9\n", + "-1651.9\n", + "-1652.9\n", + "-1653.9\n", + "-1654.9\n", + "-1655.9\n", + "-1656.9\n", + "-1657.9\n", + "-1658.9\n", + "-1659.9\n", + "-1660.9\n", + "-1661.9\n", + "-1662.9\n", + "-1663.9\n", + "-1664.9\n", + "-1665.9\n", + "-1666.9\n", + "-1667.9\n", + "-1668.9\n", + "-1669.9\n", + "-1670.9\n", + "-1671.9\n", + "-1672.9\n", + "-1673.9\n", + "-1674.9\n", + "-1675.9\n", + "-1676.9\n", + "-1677.9\n", + "-1678.9\n", + "-1679.9\n", + "-1680.9\n", + "-1681.9\n", + "-1682.9\n", + "-1683.9\n", + "-1684.9\n", + "-1685.9\n", + "-1686.9\n", + "-1687.9\n", + "-1688.9\n", + "-1689.9\n", + "-1690.9\n", + "-1691.9\n", + "-1692.9\n", + "-1693.9\n", + "-1694.9\n", + "-1695.9\n", + "-1696.9\n", + "-1697.9\n", + "-1698.9\n", + "-1699.9\n", + "-1700.9\n", + "-1701.9\n", + "-1702.9\n", + "-1703.9\n", + "-1704.9\n", + "-1705.9\n", + "-1706.9\n", + "-1707.9\n", + "-1708.9\n", + "-1709.9\n", + "-1710.9\n", + "-1711.9\n", + "-1712.9\n", + "-1713.9\n", + "-1714.9\n", + "-1715.9\n", + "-1716.9\n", + "-1717.9\n", + "-1718.9\n", + "-1719.9\n", + "-1720.9\n", + "-1721.9\n", + "-1722.9\n", + "-1723.9\n", + "-1724.9\n", + "-1725.9\n", + "-1726.9\n", + "-1727.9\n", + "-1728.9\n", + "-1729.9\n", + "-1730.9\n", + "-1731.9\n", + "-1732.9\n", + "-1733.9\n", + "-1734.9\n", + "-1735.9\n", + "-1736.9\n", + "-1737.9\n", + "-1738.9\n", + "-1739.9\n", + "-1740.9\n", + "-1741.9\n", + "-1742.9\n", + "-1743.9\n", + "-1744.9\n", + "-1745.9\n", + "-1746.9\n", + "-1747.9\n", + "-1748.9\n", + "-1749.9\n", + "-1750.9\n", + "-1751.9\n", + "-1752.9\n", + "-1753.9\n", + "-1754.9\n", + "-1755.9\n", + "-1756.9\n", + "-1757.9\n", + "-1758.9\n", + "-1759.9\n", + "-1760.9\n", + "-1761.9\n", + "-1762.9\n", + "-1763.9\n", + "-1764.9\n", + "-1765.9\n", + "-1766.9\n", + "-1767.9\n", + "-1768.9\n", + "-1769.9\n", + "-1770.9\n", + "-1771.9\n", + "-1772.9\n", + "-1773.9\n", + "-1774.9\n", + "-1775.9\n", + "-1776.9\n", + "-1777.9\n", + "-1778.9\n", + "-1779.9\n", + "-1780.9\n", + "-1781.9\n", + "-1782.9\n", + "-1783.9\n", + "-1784.9\n", + "-1785.9\n", + "-1786.9\n", + "-1787.9\n", + "-1788.9\n", + "-1789.9\n", + "-1790.9\n", + "-1791.9\n", + "-1792.9\n", + "-1793.9\n", + "-1794.9\n", + "-1795.9\n", + "-1796.9\n", + "-1797.9\n", + "-1798.9\n", + "-1799.9\n", + "-1800.9\n", + "-1801.9\n", + "-1802.9\n", + "-1803.9\n", + "-1804.9\n", + "-1805.9\n", + "-1806.9\n", + "-1807.9\n", + "-1808.9\n", + "-1809.9\n", + "-1810.9\n", + "-1811.9\n", + "-1812.9\n", + "-1813.9\n", + "-1814.9\n", + "-1815.9\n", + "-1816.9\n", + "-1817.9\n", + "-1818.9\n", + "-1819.9\n", + "-1820.9\n", + "-1821.9\n", + "-1822.9\n", + "-1823.9\n", + "-1824.9\n", + "-1825.9\n", + "-1826.9\n", + "-1827.9\n", + "-1828.9\n", + "-1829.9\n", + "-1830.9\n", + "-1831.9\n", + "-1832.9\n", + "-1833.9\n", + "-1834.9\n", + "-1835.9\n", + "-1836.9\n", + "-1837.9\n", + "-1838.9\n", + "-1839.9\n", + "-1840.9\n", + "-1841.9\n", + "-1842.9\n", + "-1843.9\n", + "-1844.9\n", + "-1845.9\n", + "-1846.9\n", + "-1847.9\n", + "-1848.9\n", + "-1849.9\n", + "-1850.9\n", + "-1851.9\n", + "-1852.9\n", + "-1853.9\n", + "-1854.9\n", + "-1855.9\n", + "-1856.9\n", + "-1857.9\n", + "-1858.9\n", + "-1859.9\n", + "-1860.9\n", + "-1861.9\n", + "-1862.9\n", + "-1863.9\n", + "-1864.9\n", + "-1865.9\n", + "-1866.9\n", + "-1867.9\n", + "-1868.9\n", + "-1869.9\n", + "-1870.9\n", + "-1871.9\n", + "-1872.9\n", + "-1873.9\n", + "-1874.9\n", + "-1875.9\n", + "-1876.9\n", + "-1877.9\n", + "-1878.9\n", + "-1879.9\n", + "-1880.9\n", + "-1881.9\n", + "-1882.9\n", + "-1883.9\n", + "-1884.9\n", + "-1885.9\n", + "-1886.9\n", + "-1887.9\n", + "-1888.9\n", + "-1889.9\n", + "-1890.9\n", + "-1891.9\n", + "-1892.9\n", + "-1893.9\n", + "-1894.9\n", + "-1895.9\n", + "-1896.9\n", + "-1897.9\n", + "-1898.9\n", + "-1899.9\n", + "-1900.9\n", + "-1901.9\n", + "-1902.9\n", + "-1903.9\n", + "-1904.9\n", + "-1905.9\n", + "-1906.9\n", + "-1907.9\n", + "-1908.9\n", + "-1909.9\n", + "-1910.9\n", + "-1911.9\n", + "-1912.9\n", + "-1913.9\n", + "-1914.9\n", + "-1915.9\n", + "-1916.9\n", + "-1917.9\n", + "-1918.9\n", + "-1919.9\n", + "-1920.9\n", + "-1921.9\n", + "-1922.9\n", + "-1923.9\n", + "-1924.9\n", + "-1925.9\n", + "-1926.9\n", + "-1927.9\n", + "-1928.9\n", + "-1929.9\n", + "-1930.9\n", + "-1931.9\n", + "-1932.9\n", + "-1933.9\n", + "-1934.9\n", + "-1935.9\n", + "-1936.9\n", + "-1937.9\n", + "-1938.9\n", + "-1939.9\n", + "-1940.9\n", + "-1941.9\n", + "-1942.9\n", + "-1943.9\n", + "-1944.9\n", + "-1945.9\n", + "-1946.9\n", + "-1947.9\n", + "-1948.9\n", + "-1949.9\n", + "-1950.9\n", + "-1951.9\n", + "-1952.9\n", + "-1953.9\n", + "-1954.9\n", + "-1955.9\n", + "-1956.9\n", + "-1957.9\n", + "-1958.9\n", + "-1959.9\n", + "-1960.9\n", + "-1961.9\n", + "-1962.9\n", + "-1963.9\n", + "-1964.9\n", + "-1965.9\n", + "-1966.9\n", + "-1967.9\n", + "-1968.9\n", + "-1969.9\n", + "-1970.9\n", + "-1971.9\n", + "-1972.9\n", + "-1973.9\n", + "-1974.9\n", + "-1975.9\n", + "-1976.9\n", + "-1977.9\n", + "-1978.9\n", + "-1979.9\n", + "-1980.9\n", + "-1981.9\n", + "-1982.9\n", + "-1983.9\n", + "-1984.9\n", + "-1985.9\n", + "-1986.9\n", + "-1987.9\n", + "-1988.9\n", + "-1989.9\n", + "-1990.9\n", + "-1991.9\n", + "-1992.9\n", + "-1993.9\n", + "-1994.9\n", + "-1995.9\n", + "-1996.9\n", + "-1997.9\n", + "-1998.9\n", + "-1999.9\n", + "-2000.9\n", + "-2001.9\n", + "-2002.9\n", + "-2003.9\n", + "-2004.9\n", + "-2005.9\n", + "-2006.9\n", + "-2007.9\n", + "-2008.9\n", + "-2009.9\n", + "-2010.9\n", + "-2011.9\n", + "-2012.9\n", + "-2013.9\n", + "-2014.9\n", + "-2015.9\n", + "-2016.9\n", + "-2017.9\n", + "-2018.9\n", + "-2019.9\n", + "-2020.9\n", + "-2021.9\n", + "-2022.9\n", + "-2023.9\n", + "-2024.9\n", + "-2025.9\n", + "-2026.9\n", + "-2027.9\n", + "-2028.9\n", + "-2029.9\n", + "-2030.9\n", + "-2031.9\n", + "-2032.9\n", + "-2033.9\n", + "-2034.9\n", + "-2035.9\n", + "-2036.9\n", + "-2037.9\n", + "-2038.9\n", + "-2039.9\n", + "-2040.9\n", + "-2041.9\n", + "-2042.9\n", + "-2043.9\n", + "-2044.9\n", + "-2045.9\n", + "-2046.9\n", + "-2047.9\n", + "-2048.9\n", + "-2049.9\n", + "-2050.9\n", + "-2051.9\n", + "-2052.9\n", + "-2053.9\n", + "-2054.9\n", + "-2055.9\n", + "-2056.9\n", + "-2057.9\n", + "-2058.9\n", + "-2059.9\n", + "-2060.9\n", + "-2061.9\n", + "-2062.9\n", + "-2063.9\n", + "-2064.9\n", + "-2065.9\n", + "-2066.9\n", + "-2067.9\n", + "-2068.9\n", + "-2069.9\n", + "-2070.9\n", + "-2071.9\n", + "-2072.9\n", + "-2073.9\n", + "-2074.9\n", + "-2075.9\n", + "-2076.9\n", + "-2077.9\n", + "-2078.9\n", + "-2079.9\n", + "-2080.9\n", + "-2081.9\n", + "-2082.9\n", + "-2083.9\n", + "-2084.9\n", + "-2085.9\n", + "-2086.9\n", + "-2087.9\n", + "-2088.9\n", + "-2089.9\n", + "-2090.9\n", + "-2091.9\n", + "-2092.9\n", + "-2093.9\n", + "-2094.9\n", + "-2095.9\n", + "-2096.9\n", + "-2097.9\n", + "-2098.9\n", + "-2099.9\n", + "-2100.9\n", + "-2101.9\n", + "-2102.9\n", + "-2103.9\n", + "-2104.9\n", + "-2105.9\n", + "-2106.9\n", + "-2107.9\n", + "-2108.9\n", + "-2109.9\n", + "-2110.9\n", + "-2111.9\n", + "-2112.9\n", + "-2113.9\n", + "-2114.9\n", + "-2115.9\n", + "-2116.9\n", + "-2117.9\n", + "-2118.9\n", + "-2119.9\n", + "-2120.9\n", + "-2121.9\n", + "-2122.9\n", + "-2123.9\n", + "-2124.9\n", + "-2125.9\n", + "-2126.9\n", + "-2127.9\n", + "-2128.9\n", + "-2129.9\n", + "-2130.9\n", + "-2131.9\n", + "-2132.9\n", + "-2133.9\n", + "-2134.9\n", + "-2135.9\n", + "-2136.9\n", + "-2137.9\n", + "-2138.9\n", + "-2139.9\n", + "-2140.9\n", + "-2141.9\n", + "-2142.9\n", + "-2143.9\n", + "-2144.9\n", + "-2145.9\n", + "-2146.9\n", + "-2147.9\n", + "-2148.9\n", + "-2149.9\n", + "-2150.9\n", + "-2151.9\n", + "-2152.9\n", + "-2153.9\n", + "-2154.9\n", + "-2155.9\n", + "-2156.9\n", + "-2157.9\n", + "-2158.9\n", + "-2159.9\n", + "-2160.9\n", + "-2161.9\n", + "-2162.9\n", + "-2163.9\n", + "-2164.9\n", + "-2165.9\n", + "-2166.9\n", + "-2167.9\n", + "-2168.9\n", + "-2169.9\n", + "-2170.9\n", + "-2171.9\n", + "-2172.9\n", + "-2173.9\n", + "-2174.9\n", + "-2175.9\n", + "-2176.9\n", + "-2177.9\n", + "-2178.9\n", + "-2179.9\n", + "-2180.9\n", + "-2181.9\n", + "-2182.9\n", + "-2183.9\n", + "-2184.9\n", + "-2185.9\n", + "-2186.9\n", + "-2187.9\n", + "-2188.9\n", + "-2189.9\n", + "-2190.9\n", + "-2191.9\n", + "-2192.9\n", + "-2193.9\n", + "-2194.9\n", + "-2195.9\n", + "-2196.9\n", + "-2197.9\n", + "-2198.9\n", + "-2199.9\n", + "-2200.9\n", + "-2201.9\n", + "-2202.9\n", + "-2203.9\n", + "-2204.9\n", + "-2205.9\n", + "-2206.9\n", + "-2207.9\n", + "-2208.9\n", + "-2209.9\n", + "-2210.9\n", + "-2211.9\n", + "-2212.9\n", + "-2213.9\n", + "-2214.9\n", + "-2215.9\n", + "-2216.9\n", + "-2217.9\n", + "-2218.9\n", + "-2219.9\n", + "-2220.9\n", + "-2221.9\n", + "-2222.9\n", + "-2223.9\n", + "-2224.9\n", + "-2225.9\n", + "-2226.9\n", + "-2227.9\n", + "-2228.9\n", + "-2229.9\n", + "-2230.9\n", + "-2231.9\n", + "-2232.9\n", + "-2233.9\n", + "-2234.9\n", + "-2235.9\n", + "-2236.9\n", + "-2237.9\n", + "-2238.9\n", + "-2239.9\n", + "-2240.9\n", + "-2241.9\n", + "-2242.9\n", + "-2243.9\n", + "-2244.9\n", + "-2245.9\n", + "-2246.9\n", + "-2247.9\n", + "-2248.9\n", + "-2249.9\n", + "-2250.9\n", + "-2251.9\n", + "-2252.9\n", + "-2253.9\n", + "-2254.9\n", + "-2255.9\n", + "-2256.9\n", + "-2257.9\n", + "-2258.9\n", + "-2259.9\n", + "-2260.9\n", + "-2261.9\n", + "-2262.9\n", + "-2263.9\n", + "-2264.9\n", + "-2265.9\n", + "-2266.9\n", + "-2267.9\n", + "-2268.9\n", + "-2269.9\n", + "-2270.9\n", + "-2271.9\n", + "-2272.9\n", + "-2273.9\n", + "-2274.9\n", + "-2275.9\n", + "-2276.9\n", + "-2277.9\n", + "-2278.9\n", + "-2279.9\n", + "-2280.9\n", + "-2281.9\n", + "-2282.9\n", + "-2283.9\n", + "-2284.9\n", + "-2285.9\n", + "-2286.9\n", + "-2287.9\n", + "-2288.9\n", + "-2289.9\n", + "-2290.9\n", + "-2291.9\n", + "-2292.9\n", + "-2293.9\n", + "-2294.9\n", + "-2295.9\n", + "-2296.9\n", + "-2297.9\n", + "-2298.9\n", + "-2299.9\n", + "-2300.9\n", + "-2301.9\n", + "-2302.9\n", + "-2303.9\n", + "-2304.9\n", + "-2305.9\n", + "-2306.9\n", + "-2307.9\n", + "-2308.9\n", + "-2309.9\n", + "-2310.9\n", + "-2311.9\n", + "-2312.9\n", + "-2313.9\n", + "-2314.9\n", + "-2315.9\n", + "-2316.9\n", + "-2317.9\n", + "-2318.9\n", + "-2319.9\n", + "-2320.9\n", + "-2321.9\n", + "-2322.9\n", + "-2323.9\n", + "-2324.9\n", + "-2325.9\n", + "-2326.9\n", + "-2327.9\n", + "-2328.9\n", + "-2329.9\n", + "-2330.9\n", + "-2331.9\n", + "-2332.9\n", + "-2333.9\n", + "-2334.9\n", + "-2335.9\n", + "-2336.9\n", + "-2337.9\n", + "-2338.9\n", + "-2339.9\n", + "-2340.9\n", + "-2341.9\n", + "-2342.9\n", + "-2343.9\n", + "-2344.9\n", + "-2345.9\n", + "-2346.9\n", + "-2347.9\n", + "-2348.9\n", + "-2349.9\n", + "-2350.9\n", + "-2351.9\n", + "-2352.9\n", + "-2353.9\n", + "-2354.9\n", + "-2355.9\n", + "-2356.9\n", + "-2357.9\n", + "-2358.9\n", + "-2359.9\n", + "-2360.9\n", + "-2361.9\n", + "-2362.9\n", + "-2363.9\n", + "-2364.9\n", + "-2365.9\n", + "-2366.9\n", + "-2367.9\n", + "-2368.9\n", + "-2369.9\n", + "-2370.9\n", + "-2371.9\n", + "-2372.9\n", + "-2373.9\n", + "-2374.9\n", + "-2375.9\n", + "-2376.9\n", + "-2377.9\n", + "-2378.9\n", + "-2379.9\n", + "-2380.9\n", + "-2381.9\n", + "-2382.9\n", + "-2383.9\n", + "-2384.9\n", + "-2385.9\n", + "-2386.9\n", + "-2387.9\n", + "-2388.9\n", + "-2389.9\n", + "-2390.9\n", + "-2391.9\n", + "-2392.9\n", + "-2393.9\n", + "-2394.9\n", + "-2395.9\n", + "-2396.9\n", + "-2397.9\n", + "-2398.9\n", + "-2399.9\n", + "-2400.9\n", + "-2401.9\n", + "-2402.9\n", + "-2403.9\n", + "-2404.9\n", + "-2405.9\n", + "-2406.9\n", + "-2407.9\n", + "-2408.9\n", + "-2409.9\n", + "-2410.9\n", + "-2411.9\n", + "-2412.9\n", + "-2413.9\n", + "-2414.9\n", + "-2415.9\n", + "-2416.9\n", + "-2417.9\n", + "-2418.9\n", + "-2419.9\n", + "-2420.9\n", + "-2421.9\n", + "-2422.9\n", + "-2423.9\n", + "-2424.9\n", + "-2425.9\n", + "-2426.9\n", + "-2427.9\n", + "-2428.9\n", + "-2429.9\n", + "-2430.9\n", + "-2431.9\n", + "-2432.9\n", + "-2433.9\n", + "-2434.9\n", + "-2435.9\n", + "-2436.9\n", + "-2437.9\n", + "-2438.9\n", + "-2439.9\n", + "-2440.9\n", + "-2441.9\n", + "-2442.9\n", + "-2443.9\n", + "-2444.9\n", + "-2445.9\n", + "-2446.9\n", + "-2447.9\n", + "-2448.9\n", + "-2449.9\n", + "-2450.9\n", + "-2451.9\n", + "-2452.9\n", + "-2453.9\n", + "-2454.9\n", + "-2455.9\n", + "-2456.9\n", + "-2457.9\n", + "-2458.9\n", + "-2459.9\n", + "-2460.9\n", + "-2461.9\n", + "-2462.9\n", + "-2463.9\n", + "-2464.9\n", + "-2465.9\n", + "-2466.9\n", + "-2467.9\n", + "-2468.9\n", + "-2469.9\n", + "-2470.9\n", + "-2471.9\n", + "-2472.9\n", + "-2473.9\n", + "-2474.9\n", + "-2475.9\n", + "-2476.9\n", + "-2477.9\n", + "-2478.9\n", + "-2479.9\n", + "-2480.9\n", + "-2481.9\n", + "-2482.9\n", + "-2483.9\n", + "-2484.9\n", + "-2485.9\n", + "-2486.9\n", + "-2487.9\n", + "-2488.9\n", + "-2489.9\n", + "-2490.9\n", + "-2491.9\n", + "-2492.9\n", + "-2493.9\n", + "-2494.9\n", + "-2495.9\n", + "-2496.9\n", + "-2497.9\n", + "-2498.9\n", + "-2499.9\n", + "-2500.9\n", + "-2501.9\n", + "-2502.9\n", + "-2503.9\n", + "-2504.9\n", + "-2505.9\n", + "-2506.9\n", + "-2507.9\n", + "-2508.9\n", + "-2509.9\n", + "-2510.9\n", + "-2511.9\n", + "-2512.9\n", + "-2513.9\n", + "-2514.9\n", + "-2515.9\n", + "-2516.9\n", + "-2517.9\n", + "-2518.9\n", + "-2519.9\n", + "-2520.9\n", + "-2521.9\n", + "-2522.9\n", + "-2523.9\n", + "-2524.9\n", + "-2525.9\n", + "-2526.9\n", + "-2527.9\n", + "-2528.9\n", + "-2529.9\n", + "-2530.9\n", + "-2531.9\n", + "-2532.9\n", + "-2533.9\n", + "-2534.9\n", + "-2535.9\n", + "-2536.9\n", + "-2537.9\n", + "-2538.9\n", + "-2539.9\n", + "-2540.9\n", + "-2541.9\n", + "-2542.9\n", + "-2543.9\n", + "-2544.9\n", + "-2545.9\n", + "-2546.9\n", + "-2547.9\n", + "-2548.9\n", + "-2549.9\n", + "-2550.9\n", + "-2551.9\n", + "-2552.9\n", + "-2553.9\n", + "-2554.9\n", + "-2555.9\n", + "-2556.9\n", + "-2557.9\n", + "-2558.9\n", + "-2559.9\n", + "-2560.9\n", + "-2561.9\n", + "-2562.9\n", + "-2563.9\n", + "-2564.9\n", + "-2565.9\n", + "-2566.9\n", + "-2567.9\n", + "-2568.9\n", + "-2569.9\n", + "-2570.9\n", + "-2571.9\n", + "-2572.9\n", + "-2573.9\n", + "-2574.9\n", + "-2575.9\n", + "-2576.9\n", + "-2577.9\n", + "-2578.9\n", + "-2579.9\n", + "-2580.9\n", + "-2581.9\n", + "-2582.9\n", + "-2583.9\n", + "-2584.9\n", + "-2585.9\n", + "-2586.9\n", + "-2587.9\n", + "-2588.9\n", + "-2589.9\n", + "-2590.9\n", + "-2591.9\n", + "-2592.9\n", + "-2593.9\n", + "-2594.9\n", + "-2595.9\n", + "-2596.9\n", + "-2597.9\n", + "-2598.9\n", + "-2599.9\n", + "-2600.9\n", + "-2601.9\n", + "-2602.9\n", + "-2603.9\n", + "-2604.9\n", + "-2605.9\n", + "-2606.9\n", + "-2607.9\n", + "-2608.9\n", + "-2609.9\n", + "-2610.9\n", + "-2611.9\n", + "-2612.9\n", + "-2613.9\n", + "-2614.9\n", + "-2615.9\n", + "-2616.9\n", + "-2617.9\n", + "-2618.9\n", + "-2619.9\n", + "-2620.9\n", + "-2621.9\n", + "-2622.9\n", + "-2623.9\n", + "-2624.9\n", + "-2625.9\n", + "-2626.9\n", + "-2627.9\n", + "-2628.9\n", + "-2629.9\n", + "-2630.9\n", + "-2631.9\n", + "-2632.9\n", + "-2633.9\n", + "-2634.9\n", + "-2635.9\n", + "-2636.9\n", + "-2637.9\n", + "-2638.9\n", + "-2639.9\n", + "-2640.9\n", + "-2641.9\n", + "-2642.9\n", + "-2643.9\n", + "-2644.9\n", + "-2645.9\n", + "-2646.9\n", + "-2647.9\n", + "-2648.9\n", + "-2649.9\n", + "-2650.9\n", + "-2651.9\n", + "-2652.9\n", + "-2653.9\n", + "-2654.9\n", + "-2655.9\n", + "-2656.9\n", + "-2657.9\n", + "-2658.9\n", + "-2659.9\n", + "-2660.9\n", + "-2661.9\n", + "-2662.9\n", + "-2663.9\n", + "-2664.9\n", + "-2665.9\n", + "-2666.9\n", + "-2667.9\n", + "-2668.9\n", + "-2669.9\n", + "-2670.9\n", + "-2671.9\n", + "-2672.9\n", + "-2673.9\n", + "-2674.9\n", + "-2675.9\n", + "-2676.9\n", + "-2677.9\n", + "-2678.9\n", + "-2679.9\n", + "-2680.9\n", + "-2681.9\n", + "-2682.9\n", + "-2683.9\n", + "-2684.9\n", + "-2685.9\n", + "-2686.9\n", + "-2687.9\n", + "-2688.9\n", + "-2689.9\n", + "-2690.9\n", + "-2691.9\n", + "-2692.9\n", + "-2693.9\n", + "-2694.9\n", + "-2695.9\n", + "-2696.9\n", + "-2697.9\n", + "-2698.9\n", + "-2699.9\n", + "-2700.9\n", + "-2701.9\n", + "-2702.9\n", + "-2703.9\n", + "-2704.9\n", + "-2705.9\n", + "-2706.9\n", + "-2707.9\n", + "-2708.9\n", + "-2709.9\n", + "-2710.9\n", + "-2711.9\n", + "-2712.9\n", + "-2713.9\n", + "-2714.9\n", + "-2715.9\n", + "-2716.9\n", + "-2717.9\n", + "-2718.9\n", + "-2719.9\n", + "-2720.9\n", + "-2721.9\n", + "-2722.9\n", + "-2723.9\n", + "-2724.9\n", + "-2725.9\n", + "-2726.9\n", + "-2727.9\n", + "-2728.9\n", + "-2729.9\n", + "-2730.9\n", + "-2731.9\n", + "-2732.9\n", + "-2733.9\n", + "-2734.9\n", + "-2735.9\n", + "-2736.9\n", + "-2737.9\n", + "-2738.9\n", + "-2739.9\n", + "-2740.9\n", + "-2741.9\n", + "-2742.9\n", + "-2743.9\n", + "-2744.9\n", + "-2745.9\n", + "-2746.9\n", + "-2747.9\n", + "-2748.9\n", + "-2749.9\n", + "-2750.9\n", + "-2751.9\n", + "-2752.9\n", + "-2753.9\n", + "-2754.9\n", + "-2755.9\n", + "-2756.9\n", + "-2757.9\n", + "-2758.9\n", + "-2759.9\n", + "-2760.9\n", + "-2761.9\n", + "-2762.9\n", + "-2763.9\n", + "-2764.9\n", + "-2765.9\n", + "-2766.9\n", + "-2767.9\n", + "-2768.9\n", + "-2769.9\n", + "-2770.9\n", + "-2771.9\n", + "-2772.9\n", + "-2773.9\n", + "-2774.9\n", + "-2775.9\n", + "-2776.9\n", + "-2777.9\n", + "-2778.9\n", + "-2779.9\n", + "-2780.9\n", + "-2781.9\n", + "-2782.9\n", + "-2783.9\n", + "-2784.9\n", + "-2785.9\n", + "-2786.9\n", + "-2787.9\n", + "-2788.9\n", + "-2789.9\n", + "-2790.9\n", + "-2791.9\n", + "-2792.9\n", + "-2793.9\n", + "-2794.9\n", + "-2795.9\n", + "-2796.9\n", + "-2797.9\n", + "-2798.9\n", + "-2799.9\n", + "-2800.9\n", + "-2801.9\n", + "-2802.9\n", + "-2803.9\n", + "-2804.9\n", + "-2805.9\n", + "-2806.9\n", + "-2807.9\n", + "-2808.9\n", + "-2809.9\n", + "-2810.9\n", + "-2811.9\n", + "-2812.9\n", + "-2813.9\n", + "-2814.9\n", + "-2815.9\n", + "-2816.9\n", + "-2817.9\n", + "-2818.9\n", + "-2819.9\n", + "-2820.9\n", + "-2821.9\n", + "-2822.9\n", + "-2823.9\n", + "-2824.9\n", + "-2825.9\n", + "-2826.9\n", + "-2827.9\n", + "-2828.9\n", + "-2829.9\n", + "-2830.9\n", + "-2831.9\n", + "-2832.9\n", + "-2833.9\n", + "-2834.9\n", + "-2835.9\n", + "-2836.9\n", + "-2837.9\n", + "-2838.9\n", + "-2839.9\n", + "-2840.9\n", + "-2841.9\n", + "-2842.9\n", + "-2843.9\n", + "-2844.9\n", + "-2845.9\n", + "-2846.9\n", + "-2847.9\n", + "-2848.9\n", + "-2849.9\n", + "-2850.9\n", + "-2851.9\n", + "-2852.9\n", + "-2853.9\n", + "-2854.9\n", + "-2855.9\n", + "-2856.9\n", + "-2857.9\n", + "-2858.9\n", + "-2859.9\n", + "-2860.9\n", + "-2861.9\n", + "-2862.9\n", + "-2863.9\n", + "-2864.9\n", + "-2865.9\n", + "-2866.9\n", + "-2867.9\n", + "-2868.9\n", + "-2869.9\n", + "-2870.9\n", + "-2871.9\n", + "-2872.9\n", + "-2873.9\n", + "-2874.9\n", + "-2875.9\n", + "-2876.9\n", + "-2877.9\n", + "-2878.9\n", + "-2879.9\n", + "-2880.9\n", + "-2881.9\n", + "-2882.9\n", + "-2883.9\n", + "-2884.9\n", + "-2885.9\n", + "-2886.9\n", + "-2887.9\n", + "-2888.9\n", + "-2889.9\n", + "-2890.9\n", + "-2891.9\n", + "-2892.9\n", + "-2893.9\n", + "-2894.9\n", + "-2895.9\n", + "-2896.9\n", + "-2897.9\n", + "-2898.9\n", + "-2899.9\n", + "-2900.9\n", + "-2901.9\n", + "-2902.9\n", + "-2903.9\n", + "-2904.9\n", + "-2905.9\n", + "-2906.9\n", + "-2907.9\n", + "-2908.9\n", + "-2909.9\n", + "-2910.9\n", + "-2911.9\n", + "-2912.9\n", + "-2913.9\n", + "-2914.9\n", + "-2915.9\n", + "-2916.9\n", + "-2917.9\n", + "-2918.9\n", + "-2919.9\n", + "-2920.9\n", + "-2921.9\n", + "-2922.9\n", + "-2923.9\n", + "-2924.9\n", + "-2925.9\n", + "-2926.9\n", + "-2927.9\n", + "-2928.9\n", + "-2929.9\n", + "-2930.9\n", + "-2931.9\n", + "-2932.9\n", + "-2933.9\n", + "-2934.9\n", + "-2935.9\n", + "-2936.9\n", + "-2937.9\n", + "-2938.9\n", + "-2939.9\n", + "-2940.9\n", + "-2941.9\n", + "-2942.9\n", + "-2943.9\n", + "-2944.9\n", + "-2945.9\n", + "-2946.9\n", + "-2947.9\n", + "-2948.9\n", + "-2949.9\n", + "-2950.9\n", + "-2951.9\n", + "-2952.9\n" + ] + }, + { + "ename": "RecursionError", + "evalue": "maximum recursion depth exceeded while calling a Python object", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mRecursionError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mcountdown\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m3.1\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;36mcountdown\u001b[0;34m(n)\u001b[0m\n\u001b[1;32m 9\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 10\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 11\u001b[0;31m \u001b[0mcountdown\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m \u001b[0;34m-\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "... last 1 frames repeated, from the frame below ...\n", + "\u001b[0;32m\u001b[0m in \u001b[0;36mcountdown\u001b[0;34m(n)\u001b[0m\n\u001b[1;32m 9\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 10\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 11\u001b[0;31m \u001b[0mcountdown\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m \u001b[0;34m-\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mRecursionError\u001b[0m: maximum recursion depth exceeded while calling a Python object" + ] + } + ], + "source": [ + "countdown(3.1)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "In the same way, a `RecursionError` occurs if we call `factorial()` with `3.1` instead of `3`." + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "ename": "RecursionError", + "evalue": "maximum recursion depth exceeded in comparison", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mRecursionError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mfactorial\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m3.1\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\u001b[0;34m(n)\u001b[0m\n\u001b[1;32m 10\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 11\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 12\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0mfactorial\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m \u001b[0;34m-\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "... last 1 frames repeated, from the frame below ...\n", + "\u001b[0;32m\u001b[0m in \u001b[0;36mfactorial\u001b[0;34m(n)\u001b[0m\n\u001b[1;32m 10\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 11\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 12\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0mfactorial\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m \u001b[0;34m-\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mRecursionError\u001b[0m: maximum recursion depth exceeded in comparison" + ] + } + ], + "source": [ + "factorial(3.1)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "The infinite recursions could easily be avoided by replacing `n == 0` with `n <= 0` in both functions and thereby **generalizing** them. However, even then, calling either `countdown()` or `factorial()` with a non-integer number is still *semantically* wrong.\n", + "\n", + "Errors as above are a symptom of missing **type checking**: By design, Python allows us to pass in not only integers but objects of any type as arguments to the `countdown()` and `factorial()` functions. As long as the arguments \"behave\" like integers, we do not encounter any *runtime* errors. This is the case here as the two example functions only use the `-` and `*` operators internally, and, in the context of arithmetic, a `float` object behaves like an `int` object. So, the functions keep calling themselves until Python decides with a built-in heuristic that the recursion is likely not going to end and aborts the computations with a `RecursionError`. Strictly speaking, a `RecursionError` is, of course, a *runtime* error as well." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Duck Typing" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "The missing type checking is *100% intentional* and considered a **[feature of rather than a bug](https://www.urbandictionary.com/define.php?term=It%27s%20not%20a%20bug%2C%20it%27s%20a%20feature)** in Python!\n", + "\n", + "Pythonistas use the \"technical\" term **[duck typing ](https://en.wikipedia.org/wiki/Duck_typing)** to express the idea of two objects of *different* types behaving in the *same* way in a given context. The colloquial saying goes, \"If it walks like a duck and it quacks like a duck, it must be a duck.\"\n", + "\n", + "For example, we could call `factorial()` with the `float` object `3.0`, and the recursion works out fine. So, because the `3.0` \"walks\" and \"quacks\" like a `3`, it \"must be\" a `3`." + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "6.0" + ] + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "factorial(3.0)" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "6" + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "factorial(3)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "We see similar behavior when we mix objects of types `int` and `float` with arithmetic operators. For example, `1 + 2.0` works because Python implicitly views the `1` as a `1.0` at runtime and then knows how to do floating-point arithmetic: Here, the `int` \"walks\" and \"quacks\" like a `float`." + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "3.0" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "1 + 2.0" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "3.0" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "1.0 + 2.0" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "The important lesson is that we must expect our functions to be called with objects of *any* type at runtime, as opposed to the one type we had in mind when defining the function.\n", + "\n", + "Duck typing is possible because Python is a dynamically typed language. On the contrary, in statically typed languages like C, we *must* declare (i.e., \"specify\") the data type of every parameter in a function definition. Then, a `RecursionError` as for `countdown(3.1)` or `factorial(3.1)` above could not occur. For example, if we declared the `countdown()` and `factorial()` functions to only accept `int` objects, calling the functions with a `float` argument would immediately fail *syntactically*. As a downside, we would then lose the ability to call `factorial()` with `3.0`, which is *semantically* correct nevertheless.\n", + "\n", + "So, there is no black or white answer as to which of the two language designs is better. Yet, most professional programmers have strong opinions concerning duck typing, reaching from \"love\" to \"hate.\" This is another example of how programming is a subjective art rather than \"objective\" science. Python's design is probably more appealing to beginners who intuitively regard `3` and `3.0` as interchangeable." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Type Checking & Input Validation" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "We use the built-in [isinstance() ](https://docs.python.org/3/library/functions.html#isinstance) function to make sure `factorial()` is called with an `int` object as the argument. We further **validate** the **input** by verifying that the integer is non-negative.\n", + "\n", + "Meanwhile, we also see how we manually raise exceptions with the `raise` statement (cf., [reference ](https://docs.python.org/3/reference/simple_stmts.html#the-raise-statement)), another way of controlling the flow of execution.\n", + "\n", + "The first two branches in the revised `factorial()` function act as **guardians** ensuring that the code does not produce *unexpected* runtime errors: Errors may be expected when mentioned in the docstring.\n", + "\n", + "So, in essence, we are doing *two* things here: Besides checking the type, we also enforce **domain-specific** (i.e., mathematical here) rules concerning the non-negativity of `n`." + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "def factorial(n):\n", + " \"\"\"Calculate the factorial of a number.\n", + "\n", + " Args:\n", + " n (int): number to calculate the factorial for; must be positive\n", + "\n", + " Returns:\n", + " factorial (int)\n", + "\n", + " Raises:\n", + " TypeError: if n is not an integer\n", + " ValueError: if n is negative\n", + " \"\"\"\n", + " if not isinstance(n, int):\n", + " raise TypeError(\"Factorial is only defined for integers\")\n", + " elif n < 0:\n", + " raise ValueError(\"Factorial is not defined for negative integers\")\n", + " elif n == 0:\n", + " return 1\n", + " return n * factorial(n - 1)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "The revised `factorial()` function works like the old one." + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 36, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "factorial(0)" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "6" + ] + }, + "execution_count": 37, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "factorial(3)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "Instead of running into a situation of infinite recursion, we now receive specific error messages." + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "ename": "TypeError", + "evalue": "Factorial is only defined for integers", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mfactorial\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m3.1\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\u001b[0;34m(n)\u001b[0m\n\u001b[1;32m 13\u001b[0m \"\"\"\n\u001b[1;32m 14\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;32mnot\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[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 15\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mTypeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Factorial is only defined for integers\"\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 16\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m<\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 17\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Factorial is not defined for negative integers\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mTypeError\u001b[0m: Factorial is only defined for integers" + ] + } + ], + "source": [ + "factorial(3.1)" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "ename": "ValueError", + "evalue": "Factorial is not defined for negative integers", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mfactorial\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m-\u001b[0m\u001b[0;36m42\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\u001b[0;34m(n)\u001b[0m\n\u001b[1;32m 15\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0mTypeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Factorial is only defined for integers\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 16\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m<\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 17\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Factorial is not defined for negative integers\"\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 18\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 19\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mValueError\u001b[0m: Factorial is not defined for negative integers" + ] + } + ], + "source": [ + "factorial(-42)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "Forcing `n` to be an `int` is a very puritan way of handling the issues discussed above. So, we can *not* call `factorial()` with, for example, `3.0`." + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "ename": "TypeError", + "evalue": "Factorial is only defined for integers", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mfactorial\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m3.0\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\u001b[0;34m(n)\u001b[0m\n\u001b[1;32m 13\u001b[0m \"\"\"\n\u001b[1;32m 14\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;32mnot\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[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 15\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mTypeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Factorial is only defined for integers\"\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 16\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m<\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 17\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Factorial is not defined for negative integers\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mTypeError\u001b[0m: Factorial is only defined for integers" + ] + } + ], + "source": [ + "factorial(3.0)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Type Casting" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "A similar way to prevent an infinite recursion is to **cast** the **type** of the `n` argument with the built-in [int() ](https://docs.python.org/3/library/functions.html#int) constructor." + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "def factorial(n):\n", + " \"\"\"Calculate the factorial of a number.\n", + "\n", + " Args:\n", + " n (int): number to calculate the factorial for; must be positive\n", + "\n", + " Returns:\n", + " factorial (int)\n", + "\n", + " Raises:\n", + " TypeError: if n cannot be cast as an integer\n", + " ValueError: if n is negative\n", + " \"\"\"\n", + " n = int(n)\n", + " if n < 0:\n", + " raise ValueError(\"Factorial is not defined for negative integers\")\n", + " elif n == 0:\n", + " return 1\n", + " return n * factorial(n - 1)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "The not so strict type casting implements duck typing for `factorial()` as, for example, `3.0` \"walks\" and \"quacks\" like a `3`." + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "6" + ] + }, + "execution_count": 42, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "factorial(3)" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "6" + ] + }, + "execution_count": 43, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "factorial(3.0)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "However, if we now call `factorial()` with a non-integer `float` object like `3.1`, *no* error is raised. This is a potential source for *semantic* errors as the function runs for invalid input." + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "6" + ] + }, + "execution_count": 44, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "factorial(3.1)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "We could adjust the type casting logic such that a `TypeError` is raised for `n` arguments with non-zero decimals. " + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": { + "code_folding": [], + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "def factorial(n):\n", + " \"\"\"Calculate the factorial of a number.\n", + "\n", + " Args:\n", + " n (int): number to calculate the factorial for; must be positive\n", + "\n", + " Returns:\n", + " factorial (int)\n", + "\n", + " Raises:\n", + " TypeError: if n cannot be cast as an integer\n", + " ValueError: if n is negative\n", + " \"\"\"\n", + " if n != int(n):\n", + " raise TypeError(\"n is not integer-like; it has non-zero decimals\")\n", + " n = int(n)\n", + "\n", + " if n < 0:\n", + " raise ValueError(\"Factorial is not defined for negative integers\")\n", + " elif n == 0:\n", + " return 1\n", + " return n * factorial(n - 1)" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "6" + ] + }, + "execution_count": 46, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "factorial(3.0)" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "ename": "TypeError", + "evalue": "n is not integer-like; it has non-zero decimals", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mfactorial\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m3.1\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\u001b[0;34m(n)\u001b[0m\n\u001b[1;32m 13\u001b[0m \"\"\"\n\u001b[1;32m 14\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m!=\u001b[0m \u001b[0mint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\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[0;32m---> 15\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mTypeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"n is not integer-like; it has non-zero decimals\"\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 16\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 17\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mTypeError\u001b[0m: n is not integer-like; it has non-zero decimals" + ] + } + ], + "source": [ + "factorial(3.1)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "However, using built-in constructors for type casting leads to another subtle inconsistency. As constructors are designed to take *any* object as their argument, they do not raise a `TypeError` when called with invalid input but a `ValueError` instead. So, if we, for example, called `factorial()` with `\"text\"` as the `n` argument, we see the `ValueError` raised by [int() ](https://docs.python.org/3/library/functions.html#int) in a situation where a `TypeError` would be more appropriate." + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "ename": "ValueError", + "evalue": "invalid literal for int() with base 10: 'text'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mfactorial\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"text\"\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\u001b[0;34m(n)\u001b[0m\n\u001b[1;32m 12\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mn\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0mnegative\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 13\u001b[0m \"\"\"\n\u001b[0;32m---> 14\u001b[0;31m \u001b[0;32mif\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m!=\u001b[0m \u001b[0mint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\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[1;32m 15\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0mTypeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"n is not integer-like; it has non-zero decimals\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 16\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mValueError\u001b[0m: invalid literal for int() with base 10: 'text'" + ] + } + ], + "source": [ + "factorial(\"text\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "We could, of course, use a `try` statement to suppress the exceptions raised by [int() ](https://docs.python.org/3/library/functions.html#int) and replace them with a custom `TypeError`. However, now the implementation as a whole is more about type checking than about the actual logic solving the problem. We took this example to the extreme on purpose. In practice, we rarely see such code!" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [], + "source": [ + "def factorial(n):\n", + " \"\"\"Calculate the factorial of a number.\n", + "\n", + " Args:\n", + " n (int): number to calculate the factorial for; must be positive\n", + "\n", + " Returns:\n", + " factorial (int)\n", + "\n", + " Raises:\n", + " TypeError: if n cannot be cast as an integer\n", + " ValueError: if n is negative\n", + " \"\"\"\n", + " try:\n", + " casted_n = int(n)\n", + " except ValueError:\n", + " raise TypeError(\"n cannot be casted as an integer\") from None\n", + " else:\n", + " if n != casted_n:\n", + " raise TypeError(\"n is not integer-like; it has non-zero decimals\")\n", + " n = casted_n\n", + "\n", + " if n < 0:\n", + " raise ValueError(\"Factorial is not defined for negative integers\")\n", + " elif n == 0:\n", + " return 1\n", + " return n * factorial(n - 1)" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "ename": "TypeError", + "evalue": "n cannot be casted as an integer", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mfactorial\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"text\"\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\u001b[0;34m(n)\u001b[0m\n\u001b[1;32m 15\u001b[0m \u001b[0mcasted_n\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 16\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 17\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mTypeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"n cannot be casted as an integer\"\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 18\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 19\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m!=\u001b[0m \u001b[0mcasted_n\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mTypeError\u001b[0m: n cannot be casted as an integer" + ] + } + ], + "source": [ + "factorial(\"text\")" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "ename": "TypeError", + "evalue": "n is not integer-like; it has non-zero decimals", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mfactorial\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m3.1\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\u001b[0;34m(n)\u001b[0m\n\u001b[1;32m 18\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 19\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m!=\u001b[0m \u001b[0mcasted_n\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 20\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mTypeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"n is not integer-like; it has non-zero decimals\"\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 21\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcasted_n\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 22\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mTypeError\u001b[0m: n is not integer-like; it has non-zero decimals" + ] + } + ], + "source": [ + "factorial(3.1)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "Which way we choose for **hardening** the `factorial()` function depends on the concrete circumstances. If we are the main caller of the function ourselves, we may choose to *not* do any of the approaches at all. After all, we should be able to call our own function in the correct way. The lesson is that just because Python has no static typing, this does *not* mean that we cannot do this \"manually.\" Yet, the idea behind a dynamically typed language is to *not* deal with the types too much at all." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "## Theory of Computation" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "With everything *officially* introduced so far, Python would be what is called **[Turing complete ](https://en.wikipedia.org/wiki/Turing_completeness)**. That means that anything that could be formulated as an algorithm could be expressed with all the language features we have seen. Note that, in particular, we have *not* yet formally *introduced* the `for` and `while` statements!" + ] + } + ], + "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.6" + }, + "livereveal": { + "auto_select": "code", + "auto_select_fragment": true, + "scroll": true, + "theme": "serif" + }, + "toc": { + "base_numbering": 1, + "nav_menu": {}, + "number_sections": false, + "sideBar": true, + "skip_h1_title": true, + "title_cell": "Table of Contents", + "title_sidebar": "Contents", + "toc_cell": false, + "toc_position": { + "height": "calc(100% - 180px)", + "left": "10px", + "top": "150px", + "width": "384px" + }, + "toc_section_display": false, + "toc_window_display": false + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/README.md b/README.md index 7328211..39fafd5 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,14 @@ Alternatively, the content can be viewed in a web browser (Fizz Buzz) - [summary ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/03_conditionals/03_summary.ipynb) - [review questions ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/03_conditionals/04_review.ipynb) + - *Chapter 4*: Recursion & Looping + - [content ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/04_iteration/00_content.ipynb) + [](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/04_iteration/00_content.ipynb) + (Recursion; + Examples: Factorial, Euclid's Algorithm, & Fibonacci; + Duck Typing; + Type Casting & Checking; + Input Validation) #### Videos From d770080fd37e5c6532e6bd09081cd9e89fd5114a Mon Sep 17 00:00:00 2001 From: Alexander Hess Date: Thu, 15 Oct 2020 18:17:02 +0200 Subject: [PATCH 2/7] Add initial version of chapter 04's exercises, part 1 --- 04_iteration/00_content.ipynb | 2 +- 04_iteration/01_exercises.ipynb | 610 ++++++++++++++++++++++++ 04_iteration/static/towers_of_hanoi.gif | Bin 0 -> 197609 bytes README.md | 3 + 4 files changed, 614 insertions(+), 1 deletion(-) create mode 100644 04_iteration/01_exercises.ipynb create mode 100644 04_iteration/static/towers_of_hanoi.gif diff --git a/04_iteration/00_content.ipynb b/04_iteration/00_content.ipynb index 580d340..f7d1e41 100644 --- a/04_iteration/00_content.ipynb +++ b/04_iteration/00_content.ipynb @@ -859,7 +859,7 @@ } }, "source": [ - "##### Efficiency of Algorithms" + "#### Efficiency of Algorithms" ] }, { diff --git a/04_iteration/01_exercises.ipynb b/04_iteration/01_exercises.ipynb new file mode 100644 index 0000000..cf4b0ce --- /dev/null +++ b/04_iteration/01_exercises.ipynb @@ -0,0 +1,610 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Note**: Click on \"*Kernel*\" > \"*Restart Kernel and Run All*\" in [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) *after* finishing the exercises to ensure that your solution runs top to bottom *without* any errors. If you cannot run this file on your machine, you may want to open it [in the cloud ](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/04_iteration/01_exercises.ipynb)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Chapter 4: Recursion & Looping (Coding Exercises)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The exercises below assume that you have read the [first part ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/04_iteration/00_content.ipynb) of Chapter 4.\n", + "\n", + "The `...`'s in the code cells indicate where you need to fill in code snippets. The number of `...`'s within a code cell give you a rough idea of how many lines of code are needed to solve the task. You should not need to create any additional code cells for your final solution. However, you may want to use temporary code cells to try out some ideas." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Towers of Hanoi" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "A popular example of a problem that is solved by recursion art the **[Towers of Hanoi ](https://en.wikipedia.org/wiki/Tower_of_Hanoi)**.\n", + "\n", + "In its basic version, a tower consisting of, for example, four disks with increasing radii, is placed on the left-most of **three** adjacent spots. In the following, we refer to the number of disks as $n$, so here $n = 4$.\n", + "\n", + "The task is to move the entire tower to the right-most spot whereby **two rules** must be obeyed:\n", + "\n", + "1. Disks can only be moved individually, and\n", + "2. a disk with a larger radius must *never* be placed on a disk with a smaller one.\n", + "\n", + "Although the **[Towers of Hanoi ](https://en.wikipedia.org/wiki/Tower_of_Hanoi)** are a **classic** example, introduced by the mathematician [Édouard Lucas ](https://en.wikipedia.org/wiki/%C3%89douard_Lucas) already in 1883, it is still **actively** researched as this scholarly [article](https://www.worldscientific.com/doi/abs/10.1142/S1793830919300017?journalCode=dmaa&) published in January 2019 shows.\n", + "\n", + "Despite being so easy to formulate, the game is quite hard to solve.\n", + "\n", + "Below is an interactive illustration of the solution with the minimal number of moves for $n = 4$." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Watch the following video by [MIT](https://www.mit.edu/)'s professor [Richard Larson](https://idss.mit.edu/staff/richard-larson/) for a comprehensive introduction.\n", + "\n", + "The [MIT Blossoms Initiative](https://blossoms.mit.edu/) is primarily aimed at high school students and does not have any prerequisites.\n", + "\n", + "The video consists of three segments, the last of which is *not* necessary to have watched to solve the tasks below. So, watch the video until 37:55." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from IPython.display import YouTubeVideo\n", + "YouTubeVideo(\"UuIneNBbscc\", width=\"60%\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Video Review Questions" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Q1**: Explain for the $n = 3$ case why it can be solved as a **recursion**!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " < your answer >" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Q2**: How does the number of minimal moves needed to solve a problem with three spots and $n$ disks grow as a function of $n$? How does this relate to the answer to **Q1**?" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " < your answer >" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Q3**: The **[Towers of Hanoi ](https://en.wikipedia.org/wiki/Tower_of_Hanoi)** problem is of **exponential growth**. What does that mean? What does that imply for large $n$?" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " < your answer >" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Q4**: The video introduces the recursive relationship $Sol(4, 1, 3) = Sol(3, 1, 2) ~ \\bigoplus ~ Sol(1, 1, 3) ~ \\bigoplus ~ Sol(3, 2, 3)$. The $\\bigoplus$ is to be interpreted as some sort of \"plus\" operation. How does this \"plus\" operation work? How does this way of expressing the problem relate to the answer to **Q1**?" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " < your answer >" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Naive Translation to Python" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As most likely the first couple of tries will result in *semantic* errors, it is advisable to have some sort of **visualization tool** for the program's output: For example, an online version of the game can be found [here](https://www.mathsisfun.com/games/towerofhanoi.html)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's first **generalize** the mathematical relationship from above and then introduce the variable names used in our `sol()` implementation below.\n", + "\n", + "Unsurprisingly, the recursive relationship in the video may be generalized into:\n", + "\n", + "$Sol(n, o, d) = Sol(n-1, o, i) ~ \\bigoplus ~ Sol(1, o, d) ~ \\bigoplus ~ Sol(n-1, i, d)$\n", + "\n", + "$Sol(\\cdot)$ takes three \"arguments\" $n$, $o$, and $d$ and is defined with *three* references to itself that take modified versions of $n$, $o$, and $d$ in different orders. The middle reference, Sol(1, o, d), constitutes the \"end\" of the recursive definition: It is the problem of solving Towers of Hanoi for a \"tower\" of only one disk.\n", + "\n", + "While the first \"argument\" of $Sol(\\cdot)$ is a number that we refer to as `n_disks` below, the second and third \"arguments\" are merely **labels** for the spots, and we refer to the **roles** they take in a given problem as `origin` and `destination` below. Instead of labeling individual spots with the numbers `1`, `2`, and `3` as in the video, we may also call them `\"left\"`, `\"center\"`, and `\"right\"`. Both ways are equally correct! So, only the first \"argument\" of $Sol(\\cdot)$ is really a number!\n", + "\n", + "As an example, the notation $Sol(4, 1, 3)$ from above can then be \"translated\" into Python as either the function call `sol(4, 1, 3)` or `sol(4, \"left\", \"right\")`. This describes the problem of moving a tower consisting of `n_disks=4` disks from either the `origin=1` spot to the `destination=3` spot or from the `origin=\"left\"` spot to the `destination=\"right\"` spot.\n", + "\n", + "To adhere to the rules, an `intermediate` spot $i$ is needed. In `sol()` below, this is a temporary variable within a function call and *not* a parameter of the function itself." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In summary, to move a tower consisting of `n_disks` (= $n$) disks from an `origin` (= $o$) to a `destination` (= $d$), three steps must be executed:\n", + "\n", + "1. Move the tower's topmost `n_disks - 1` (= $n - 1$) disks from the `origin` (= $o$) to an `intermediate` (= $i$) spot (= **Sub-Problem 1**),\n", + "2. move the remaining and largest disk from the `origin` (= $o$) to the `destination` (= $d$), and\n", + "3. move the `n_disks - 1` (= $n - 1$) disks from the `intermediate` (= $i$) spot to the `destination` (= $d$) spot (= **Sub-Problem 2**).\n", + "\n", + "The two sub-problems themselves are solved via the same *recursive* logic." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Write your answers to **Q5** to **Q7** into the skeleton of `sol()` below.\n", + "\n", + "`sol()` takes three arguments `n_disks`, `origin`, and `destination` that mirror $n$, $o$, and $d$ above.\n", + "\n", + "For now, assume that all arguments to `sol()` are `int` objects! We generalize this into real labels further below in the `hanoi()` function.\n", + "\n", + "Once completed, `sol()` should *print* out all the moves in the correct order. For example, *print* `\"1 -> 3\"` to mean \"Move the top-most `n_disks - 1` disks from spot `1` to spot `3`.\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def sol(n_disks, origin, destination):\n", + " \"\"\"A naive implementation of Towers of Hanoi.\n", + "\n", + " This function prints out the moves to solve a Towers of Hanoi problem.\n", + "\n", + " Args:\n", + " n_disks (int): number of disks in the tower\n", + " origin (int): spot of the tower at the start; 1, 2, or 3\n", + " destination (int): spot of the tower at the end; 1, 2, or 3\n", + " \"\"\"\n", + " # answer to Q5\n", + " ...\n", + " ...\n", + "\n", + " # answer to Q6\n", + " ...\n", + " ...\n", + " ...\n", + " ...\n", + " ...\n", + " ...\n", + " ...\n", + " ...\n", + " ...\n", + " ...\n", + " ...\n", + " ...\n", + "\n", + " # answer to Q7\n", + " ...\n", + " ...\n", + " ..." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Q5**: What is the `n_disks` argument when the function reaches its **base case**? Check for the base case with a simple `if` statement and return from the function using the **early exit** pattern!\n", + "\n", + "Hint: The base case in the Python implementation may be slightly different than the one shown in the generalized mathematical relationship above!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Q6**: If not in the base case, `sol()` determines the `intermediate` spot given concrete `origin` and `destination` arguments. For example, if called with `origin=1` and `destination=2`, `intermediate` must be `3`.\n", + "\n", + "Add *one* compound `if` statement to `sol()` that has a branch for *every* possible `origin`-`destination`-pair that assigns the correct temporary spot to a variable `intermediate`.\n", + "\n", + "Hint: How many 2-tuples of 3 elements can there be if the order matters?" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Q7**: `sol()` calls itself *two* more times with the correct 2-tuples chosen from the three available spots `origin`, `intermediate`, and `destination`.\n", + "\n", + "*In between* the two recursive function calls, use [print() ](https://docs.python.org/3/library/functions.html#print) to print out from where to where the \"remaining and largest\" disk has to be moved!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Q8**: Execute the code cells below and confirm that the moves are correct!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "sol(1, 1, 3)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "sol(2, 1, 3)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "sol(3, 1, 3)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "sol(4, 1, 3)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Pythonic Refactoring" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The previous `sol()` implementation does the job, but the conditional statement is unnecessarily tedious. \n", + "\n", + "Let's create a concise `hanoi()` function that, in addition to a positional `n_disks` argument, takes three keyword-only arguments `origin`, `intermediate`, and `destination` with default values `\"left\"`, `\"center\"`, and `\"right\"`.\n", + "\n", + "Write your answers to **Q9** and **Q10** into the subsequent code cell and finalize `hanoi()`!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def hanoi(n_disks, *, origin=\"left\", intermediate=\"center\", destination=\"right\"):\n", + " \"\"\"A Pythonic implementation of Towers of Hanoi.\n", + "\n", + " This function prints out the moves to solve a Towers of Hanoi problem.\n", + "\n", + " Args:\n", + " n_disks (int): number of disks in the tower\n", + " origin (str, optional): label for the spot of the tower at the start\n", + " intermediate (str, optional): label for the intermediate spot\n", + " destination (str, optional): label for the spot of the tower at the end\n", + " \"\"\"\n", + " # answer to Q9\n", + " ...\n", + " ...\n", + "\n", + " # answer to Q10\n", + " ...\n", + " ...\n", + " ..." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Q9**: Copy the base case from `sol()`!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Q10**: Instead of conditional logic, `hanoi()` calls itself *two* times with the *three* arguments `origin`, `intermediate`, and `destination` passed on in a *different* order.\n", + "\n", + "Figure out how the arguments are passed on in the two recursive `hanoi()` calls and finish `hanoi()`.\n", + "\n", + "Hint: Do not forget to use [print() ](https://docs.python.org/3/library/functions.html#print) to print out the moves!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Q11**: Execute the code cells below and confirm that the moves are correct!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "hanoi(1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "hanoi(2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "hanoi(3)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "hanoi(4)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We could, of course, also use *numeric* labels for the three steps like so." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "hanoi(3, origin=1, intermediate=2, destination=3)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Passing a Value \"down\" the Recursion Tree" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The above `hanoi()` prints the optimal solution's moves in the correct order but fails to label each move with an order number. This is built in the `hanoi_ordered()` function below by passing on a \"private\" `_offset` argument \"down\" the recursion tree. The leading underscore `_` in the parameter name indicates that it is *not* to be used by the caller of the function. That is also why the parameter is *not* mentioned in the docstring.\n", + "\n", + "Write your answers to **Q12** and **Q13** into the subsequent code cell and finalize `hanoi_ordered()`! As the logic gets a bit \"involved,\" `hanoi_ordered()` below is almost finished." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def hanoi_ordered(n_disks, *, origin=\"left\", intermediate=\"center\", destination=\"right\", _offset=None):\n", + " \"\"\"A Pythonic implementation of Towers of Hanoi.\n", + "\n", + " This function prints out the moves to solve a Towers of Hanoi problem.\n", + " Each move is labeled with an order number.\n", + "\n", + " Args:\n", + " n_disks (int): number of disks in the tower\n", + " origin (str, optional): label for the spot of the tower at the start\n", + " intermediate (str, optional): label for the intermediate spot\n", + " destination (str, optional): label for the spot of the tower at the end\n", + " \"\"\"\n", + " # answer to Q12\n", + " ...\n", + " ...\n", + "\n", + " total = (2 ** n_disks - 1)\n", + " half = (2 ** (n_disks - 1) - 1)\n", + " count = total - half\n", + "\n", + " if _offset is not None:\n", + " count += _offset\n", + "\n", + " # answer to Q18\n", + " hanoi_ordered(..., _offset=_offset)\n", + " ...\n", + " hanoi_ordered(..., _offset=count)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Q12**: Copy the base case from the original `hanoi()`!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Q13**: Complete the two recursive function calls with the same arguments as in `hanoi()`! Do *not* change the already filled in `offset` arguments!\n", + "\n", + "Then, adjust the use of [print() ](https://docs.python.org/3/library/functions.html#print) from above to print out the moves with their order number!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Q14**: Execute the code cells below and confirm that the order numbers are correct!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "hanoi_ordered(1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "hanoi_ordered(2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "hanoi_ordered(3)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "hanoi_ordered(4)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Lastly, it is to be mentioned that for problem instances with a small `n_disks` argument, it is easier to collect all the moves first in a `list` object and then add the order number with the [enumerate() ](https://docs.python.org/3/library/functions.html#enumerate) built-in." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Open Question" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Q15**: Conducting your own research on the internet, what can you say about generalizing the **[Towers of Hanoi ](https://en.wikipedia.org/wiki/Tower_of_Hanoi)** problem to a setting with *more than three* landing spots?" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " < your answer >" + ] + } + ], + "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.6" + }, + "toc": { + "base_numbering": 1, + "nav_menu": {}, + "number_sections": false, + "sideBar": true, + "skip_h1_title": true, + "title_cell": "Table of Contents", + "title_sidebar": "Contents", + "toc_cell": false, + "toc_position": {}, + "toc_section_display": false, + "toc_window_display": false + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/04_iteration/static/towers_of_hanoi.gif b/04_iteration/static/towers_of_hanoi.gif new file mode 100644 index 0000000000000000000000000000000000000000..7ab13d43bcb28bf830b0d864cb72062ed393ec2d GIT binary patch literal 197609 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®usM#|8+M$%bN-%|4p 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 Hy8QnDu6(%i literal 0 HcmV?d00001 diff --git a/README.md b/README.md index 39fafd5..6843c25 100644 --- a/README.md +++ b/README.md @@ -95,6 +95,9 @@ Alternatively, the content can be viewed in a web browser Duck Typing; Type Casting & Checking; Input Validation) + - [exercises ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/04_iteration/01_exercises.ipynb) + [](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/04_iteration/01_exercises.ipynb) + (Towers of Hanoi) #### Videos From 76ef753ffa95b6bd45e617b5b609e04384b63a53 Mon Sep 17 00:00:00 2001 From: Alexander Hess Date: Thu, 15 Oct 2020 18:35:12 +0200 Subject: [PATCH 3/7] Add initial version of chapter 04, part 2 --- 04_iteration/02_content.ipynb | 1300 +++++++++++++++++++++++++++++++++ README.md | 5 + 2 files changed, 1305 insertions(+) create mode 100644 04_iteration/02_content.ipynb diff --git a/04_iteration/02_content.ipynb b/04_iteration/02_content.ipynb new file mode 100644 index 0000000..7fb3eb3 --- /dev/null +++ b/04_iteration/02_content.ipynb @@ -0,0 +1,1300 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "**Note**: Click on \"*Kernel*\" > \"*Restart Kernel and Clear All Outputs*\" in [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) *before* reading this notebook to reset its output. If you cannot run this file on your machine, you may want to open it [in the cloud ](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/04_iteration/02_content.ipynb)." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "# Chapter 4: Recursion & Looping (continued)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "After learning about the concept of **recursion** in the [first part ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/04_iteration/00_content.ipynb) of this chapter, we look at other ways of running code repeatedly, namely **looping** with the `for` and `while` statements. We start with the latter as it is more generic. Throughout this second part of the chapter, we revisit the same examples from the first part to show how recursion and looping are really two sides of the same coin." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## The `while` Statement" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "Whereas functions combined with `if` statements suffice to model any repetitive logic, Python comes with a compound `while` statement (cf., [reference ](https://docs.python.org/3/reference/compound_stmts.html#the-while-statement)) that often makes it easier to implement iterative ideas.\n", + "\n", + "It consists of a header line with a boolean expression followed by an indented code block. Before the first and after every execution of the code block, the boolean expression is evaluated, and if it is (still) equal to `True`, the code block runs (again). Eventually, some variable referenced in the boolean expression is changed in the code block such that the condition becomes `False`.\n", + "\n", + "If the condition is `False` before the first iteration, the entire code block is *never* executed. As the flow of control keeps \"looping\" (i.e., more formally, **iterating**) back to the beginning of the code block, this concept is also called a `while`-loop and each pass through the loop an **iteration**." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "### Trivial Example: Countdown (revisited)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "Let's rewrite the `countdown()` example in an iterative style. We also build in **input validation** by allowing the function only to be called with strictly positive integers. As any positive integer hits $0$ at some point when iteratively decremented by $1$, `countdown()` is guaranteed to **terminate**. Also, the base case is now handled at the end of the function, which commonly happens with iterative solutions to problems." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "code_folding": [], + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "def countdown(n):\n", + " \"\"\"Print a countdown until the party starts.\n", + "\n", + " Args:\n", + " n (int): seconds until the party begins; must be positive\n", + " \"\"\"\n", + " while n != 0:\n", + " print(n)\n", + " n -= 1\n", + "\n", + " print(\"Happy new Year!\")" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "3\n", + "2\n", + "1\n", + "Happy new Year!\n" + ] + } + ], + "source": [ + "countdown(3)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "As [PythonTutor ](http://pythontutor.com/visualize.html#code=def%20countdown%28n%29%3A%0A%20%20%20%20while%20n%20!%3D%200%3A%0A%20%20%20%20%20%20%20%20print%28n%29%0A%20%20%20%20%20%20%20%20n%20-%3D%201%0A%0A%20%20%20%20print%28%22Happy%20new%20Year!%22%29%0A%0Acountdown%283%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false) shows, there is a subtle but essential difference in the way a `while` statement is treated in memory: In short, `while` statements can *not* run into a `RecursionError` as only *one* frame is needed to manage the names. After all, there is only *one* function call to be made. For typical day-to-day applications, this difference is, however, not so important *unless* a problem instance becomes so big that a large (i.e., $> 3.000$) number of recursive calls must be made." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "### \"Still involved\" Example: [Euclid's Algorithm ](https://en.wikipedia.org/wiki/Euclidean_algorithm) (revisited)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "Finding the greatest common divisor of two numbers is still not so obvious when using a `while`-loop instead of a recursive formulation.\n", + "\n", + "The iterative implementation of `gcd()` below accepts any two strictly positive integers. As in any iteration through the loop, the smaller number is subtracted from the larger one, the two decremented values of `a` and `b` eventually become equal. Thus, this algorithm is also guaranteed to terminate. If one of the two numbers were negative or $0$ in the first place, `gcd()` would run forever, and not even Python could detect this. Try this out by removing the input validation and running the function with negative arguments!" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "code_folding": [], + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "def gcd(a, b):\n", + " \"\"\"Calculate the greatest common divisor of two numbers.\n", + "\n", + " Args:\n", + " a (int): first number; must be positive\n", + " b (int): second number; must be positive\n", + "\n", + " Returns:\n", + " gcd (int)\n", + " \"\"\"\n", + " while a != b:\n", + " if a > b:\n", + " a -= b\n", + " else:\n", + " b -= a\n", + "\n", + " return a" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "4" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "gcd(12, 4)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "gcd(7, 7919)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "#### Efficiency of Algorithms (continued)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "We also see that this implementation is a lot *less* efficient than its recursive counterpart which solves `gcd()` for the same two numbers `112233445566778899` and `987654321` within microseconds." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "5.32 s ± 0 ns per loop (mean ± std. dev. of 1 run, 1 loop each)\n" + ] + } + ], + "source": [ + "%%timeit -n 1 -r 1\n", + "gcd(112233445566778899, 987654321)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Infinite Loops" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "As with recursion, we must ensure that the iteration ends. For the above `countdown()` and `gcd()` examples, we could \"prove\" (i.e., at least argue in favor) that some pre-defined **termination criterion** is reached eventually. However, this cannot be done in all cases, as the following example shows." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "### \"Mystery\" Example: [Collatz Conjecture ](https://en.wikipedia.org/wiki/Collatz_conjecture)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "Let's play the following game:\n", + "- Think of any positive integer $n$.\n", + "- If $n$ is even, the next $n$ is half the old $n$.\n", + "- If $n$ is odd, multiply the old $n$ by $3$ and add $1$ to obtain the next $n$.\n", + "- Repeat these steps until you reach $1$.\n", + "\n", + "**Do we always reach the final $1$?**" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "The function below implements this game. Does it always reach $1$? No one has proven it so far! We include some input validation as before because `collatz()` would for sure not terminate if we called it with a negative number. Further, the Collatz sequence also works for real numbers, but then we would have to study fractals (cf., [this ](https://en.wikipedia.org/wiki/Collatz_conjecture#Iterating_on_real_or_complex_numbers)). So we restrict our example to integers only." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "code_folding": [], + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "def collatz(n):\n", + " \"\"\"Print a Collatz sequence in descending order.\n", + "\n", + " Given a positive integer n, modify it according to these rules:\n", + " - if n is even, the next n is half the previous one\n", + " - if n is odd, the next n is 3 times the previous one plus 1\n", + " - if n is 1, stop the iteration\n", + "\n", + " Args:\n", + " n (int): a positive number to start the Collatz sequence at\n", + " \"\"\"\n", + " while n != 1:\n", + " print(n, end=\" \")\n", + " if n % 2 == 0:\n", + " n //= 2 # //= to preserve the int type\n", + " else:\n", + " n = 3 * n + 1\n", + "\n", + " print(1)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "Collatz sequences do not necessarily become longer with a larger initial `n`." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "100 50 25 76 38 19 58 29 88 44 22 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1\n" + ] + } + ], + "source": [ + "collatz(100)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1000 500 250 125 376 188 94 47 142 71 214 107 322 161 484 242 121 364 182 91 274 137 412 206 103 310 155 466 233 700 350 175 526 263 790 395 1186 593 1780 890 445 1336 668 334 167 502 251 754 377 1132 566 283 850 425 1276 638 319 958 479 1438 719 2158 1079 3238 1619 4858 2429 7288 3644 1822 911 2734 1367 4102 2051 6154 3077 9232 4616 2308 1154 577 1732 866 433 1300 650 325 976 488 244 122 61 184 92 46 23 70 35 106 53 160 80 40 20 10 5 16 8 4 2 1\n" + ] + } + ], + "source": [ + "collatz(1000)" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "10000 5000 2500 1250 625 1876 938 469 1408 704 352 176 88 44 22 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1\n" + ] + } + ], + "source": [ + "collatz(10000)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "100000 50000 25000 12500 6250 3125 9376 4688 2344 1172 586 293 880 440 220 110 55 166 83 250 125 376 188 94 47 142 71 214 107 322 161 484 242 121 364 182 91 274 137 412 206 103 310 155 466 233 700 350 175 526 263 790 395 1186 593 1780 890 445 1336 668 334 167 502 251 754 377 1132 566 283 850 425 1276 638 319 958 479 1438 719 2158 1079 3238 1619 4858 2429 7288 3644 1822 911 2734 1367 4102 2051 6154 3077 9232 4616 2308 1154 577 1732 866 433 1300 650 325 976 488 244 122 61 184 92 46 23 70 35 106 53 160 80 40 20 10 5 16 8 4 2 1\n" + ] + } + ], + "source": [ + "collatz(100000)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## The `for` Statement" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "Recursion and the `while` statement are two sides of the same coin. Disregarding that in the case of recursion Python internally faces some additional burden for managing the stack of frames in memory, both approaches lead to the *same* computational steps in memory. More importantly, we can formulate any recursive implementation in an iterative way and vice versa despite one of the two ways often \"feeling\" a lot more natural given a particular problem.\n", + "\n", + "So how does the compound `for` statement (cf., [reference ](https://docs.python.org/3/reference/compound_stmts.html#the-for-statement)) in this book's very first example fit into this picture? It is a *redundant* language construct to provide a *shorter* and more *convenient* syntax for common applications of the `while` statement. In programming, such additions to a language are called **syntactic sugar**. A cup of tea tastes better with sugar, but we may drink tea without sugar too.\n", + "\n", + "Consider `elements` below. Without the `for` statement, we must manage a temporary **index variable**, `index`, to loop over all the elements and also obtain the individual elements with the `[]` operator in each iteration of the loop." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "elements = [0, 1, 2, 3, 4]" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0 1 2 3 4 " + ] + } + ], + "source": [ + "index = 0\n", + "\n", + "while index < len(elements):\n", + " element = elements[index]\n", + " print(element, end=\" \")\n", + " index += 1\n", + "\n", + "del index" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "The `for` statement, on the contrary, makes the actual business logic more apparent by stripping all the **[boilerplate code ](https://en.wikipedia.org/wiki/Boilerplate_code)** away. The variable that is automatically set by Python in each iteration of the loop (i.e., `element` in the example) is called the **target variable**." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0 1 2 3 4 " + ] + } + ], + "source": [ + "for element in elements:\n", + " print(element, end=\" \")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "For sequences of integers, the [range() ](https://docs.python.org/3/library/functions.html#func-range) built-in makes the `for` statement even more convenient: It creates a `list`-like object of type `range` that generates integers \"on the fly,\" and we look closely at the underlying effects in memory in [Chapter 8 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/08_mfr/00_content.ipynb#Mapping)." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0 1 2 3 4 " + ] + } + ], + "source": [ + "for element in range(5):\n", + " print(element, end=\" \")" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "range" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "type(range(5))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "[range() ](https://docs.python.org/3/library/functions.html#func-range) takes optional `start` and `step` arguments that we use to customize the sequence of integers even more." + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1 3 5 7 9 " + ] + } + ], + "source": [ + "for element in [1, 3, 5, 7, 9]:\n", + " print(element, end=\" \")" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1 3 5 7 9 " + ] + } + ], + "source": [ + "for element in range(1, 10, 2):\n", + " print(element, end=\" \")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "### Containers vs. Iterables" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "The essential difference between the above `list` objects, `[0, 1, 2, 3, 4]` and `[1, 3, 5, 7, 9]`, and the `range` objects, `range(5)` and `range(1, 10, 2)`, is that in the former case *six* objects are created in memory *before* the `for` statement starts running, *one* `list` holding references to *five* `int` objects, whereas in the latter case only *one* `range` object is created that **generates** `int` objects one at a time *while* the `for`-loop runs.\n", + "\n", + "However, we can loop over both of them. So a natural question to ask is why Python treats objects of *different* types in the *same* way when used with a `for` statement.\n", + "\n", + "So far, the overarching storyline in this book goes like this: In Python, *everything* is an object. Besides its *identity* and *value*, every object is characterized by \"belonging\" to *one* data type that determines how the object behaves and what we may do with it.\n", + "\n", + "Now, just as we classify objects by data type, we also classify these data types (e.g., `int`, `float`, `str`, or `list`) into **abstract concepts**.\n", + "\n", + "We did this already in [Chapter 1 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/01_elements/03_content.ipynb#Who-am-I?-And-how-many?) when we described a `list` object as \"some sort of container that holds [...] references to other objects\". So, abstractly speaking, **containers** are any objects that are \"composed\" of other objects and also \"manage\" how these objects are organized. `list` objects, for example, have the property that they model an order associated with their elements. There exist, however, other container types, many of which do *not* come with an order. So, containers primarily \"contain\" other objects and have *nothing* to do with looping.\n", + "\n", + "On the contrary, the abstract concept of **iterables** is all about looping: Any object that we can loop over is, by definition, an iterable. So, `range` objects, for example, are iterables, even though they hold no references to other objects. Moreover, looping does *not* have to occur in a *predictable* order, although this is the case for both `list` and `range` objects.\n", + "\n", + "Typically, containers are iterables, and iterables are containers. Yet, only because these two concepts coincide often, we must not think of them as the same. In [Chapter 7 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/07_sequences/00_content.ipynb#Collections-vs.-Sequences), we formalize these two concepts and introduce many more. Finally, [Chapter 11 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/11_classes/00_content.ipynb) gives an explanation how abstract concepts are implemented and play together.\n", + "\n", + "Let's continue with `first_names` below as an example an illustrate what iterable containers are." + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "first_names = [\"Achim\", \"Berthold\", \"Carl\", \"Diedrich\", \"Eckardt\"]" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "The characteristic operator associated with container types is the `in` operator: It checks if a given object evaluates equal to at least one of the objects in the container. Colloquially, it checks if an object is \"contained\" in the container. Formally, this operation is called **membership testing**." + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "\"Achim\" in first_names" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "\"Alexander\" in first_names" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "The cell below shows the *exact* workings of the `in` operator: Although `3.0` is *not* contained in `elements`, it evaluates equal to the `3` that is, which is why the following expression evaluates to `True`. So, while we could colloquially say that `elements` \"contains\" `3.0`, it actually does not." + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[0, 1, 2, 3, 4]" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "elements" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "3.0 in elements" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "Similarly, the characteristic operation of an iterable type is that it supports being looped over, for example, with the `for` statement." + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Achim Berthold Carl Diedrich Eckardt " + ] + } + ], + "source": [ + "for name in first_names:\n", + " print(name, end=\" \")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "If we must have an index variable in the loop's body, we use the [enumerate() ](https://docs.python.org/3/library/functions.html#enumerate) built-in that takes an *iterable* as its argument and then generates a \"stream\" of \"pairs\" of an index variable, `i` below, and an object provided by the iterable, `name`, separated by a `,`. There is *no* need to ever revert to the `while` statement with an explicitly managed index variable to loop over an iterable object." + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1 > Achim 2 > Berthold 3 > Carl 4 > Diedrich 5 > Eckardt " + ] + } + ], + "source": [ + "for i, name in enumerate(first_names, start=1):\n", + " print(i, \">\", name, end=\" \")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "[enumerate() ](https://docs.python.org/3/library/functions.html#enumerate) takes an optional `start` argument." + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1 > Achim 2 > Berthold 3 > Carl 4 > Diedrich 5 > Eckardt " + ] + } + ], + "source": [ + "for i, name in enumerate(first_names, start=1):\n", + " print(i, \">\", name, end=\" \")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "The [zip() ](https://docs.python.org/3/library/functions.html#zip) built-in allows us to combine the elements of two or more iterables in a *pairwise* fashion: It conceptually works like a zipper for a jacket." + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [], + "source": [ + "last_names = [\"Müller\", \"Meyer\", \"Mayer\", \"Schmitt\", \"Schmidt\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Achim Müller Berthold Meyer Carl Mayer Diedrich Schmitt Eckardt Schmidt " + ] + } + ], + "source": [ + "for first_name, last_name in zip(first_names, last_names):\n", + " print(first_name, last_name, end=\" \")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "### \"Hard at first Glance\" Example: [Fibonacci Numbers ](https://en.wikipedia.org/wiki/Fibonacci_number) (revisited)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "In contrast to its recursive counterpart, the iterative `fibonacci()` function below is somewhat harder to read. For example, it is not so obvious as to how many iterations through the `for`-loop we need to make when implementing it. There is an increased risk of making an *off-by-one* error. Moreover, we need to track a `temp` variable along.\n", + "\n", + "However, one advantage of calculating Fibonacci numbers in a **forward** fashion with a `for` statement is that we could list the entire sequence in ascending order as we calculate the desired number. To show this, we added `print()` statements in `fibonacci()` below.\n", + "\n", + "We do *not* need to store the index variable in the `for`-loop's header line: That is what the underscore variable `_` indicates; we \"throw it away.\"" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": { + "code_folding": [], + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "def fibonacci(i):\n", + " \"\"\"Calculate the ith Fibonacci number.\n", + "\n", + " Args:\n", + " i (int): index of the Fibonacci number to calculate\n", + "\n", + " Returns:\n", + " ith_fibonacci (int)\n", + " \"\"\"\n", + " a = 0\n", + " b = 1\n", + " print(a, b, sep=\" \", end=\" \") # added for didactical purposes\n", + " for _ in range(i - 1):\n", + " temp = a + b\n", + " a = b\n", + " b = temp\n", + " print(b, end=\" \") # added for didactical purposes\n", + "\n", + " return b" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0 1 1 2 3 5 8 13 21 34 55 89 144 " + ] + }, + { + "data": { + "text/plain": [ + "144" + ] + }, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fibonacci(12) # = 13th number" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "##### Efficiency of Algorithms (continued)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "Another more important advantage is that now we may calculate even big Fibonacci numbers *efficiently*." + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 10946 17711 28657 46368 75025 121393 196418 317811 514229 832040 1346269 2178309 3524578 5702887 9227465 14930352 24157817 39088169 63245986 102334155 165580141 267914296 433494437 701408733 1134903170 1836311903 2971215073 4807526976 7778742049 12586269025 20365011074 32951280099 53316291173 86267571272 139583862445 225851433717 365435296162 591286729879 956722026041 1548008755920 2504730781961 4052739537881 6557470319842 10610209857723 17167680177565 27777890035288 44945570212853 72723460248141 117669030460994 190392490709135 308061521170129 498454011879264 806515533049393 1304969544928657 2111485077978050 3416454622906707 5527939700884757 8944394323791464 14472334024676221 23416728348467685 37889062373143906 61305790721611591 99194853094755497 160500643816367088 259695496911122585 420196140727489673 679891637638612258 1100087778366101931 1779979416004714189 2880067194370816120 4660046610375530309 7540113804746346429 12200160415121876738 19740274219868223167 31940434634990099905 51680708854858323072 83621143489848422977 135301852344706746049 218922995834555169026 " + ] + }, + { + "data": { + "text/plain": [ + "218922995834555169026" + ] + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fibonacci(99) # = 100th number" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "### Easy Example: [Factorial ](https://en.wikipedia.org/wiki/Factorial) (revisited)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "The iterative `factorial()` implementation is comparable to its recursive counterpart when it comes to readability. One advantage of calculating the factorial in a forward fashion is that we could track the intermediate `product` as it grows." + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "def factorial(n):\n", + " \"\"\"Calculate the factorial of a number.\n", + "\n", + " Args:\n", + " n (int): number to calculate the factorial for, must be positive\n", + "\n", + " Returns:\n", + " factorial (int)\n", + " \"\"\"\n", + " product = 1 # because 0! = 1\n", + " for i in range(1, n + 1):\n", + " product *= i\n", + " print(product, end=\" \") # added for didactical purposes\n", + "\n", + " return product" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1 2 6 " + ] + }, + { + "data": { + "text/plain": [ + "6" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "factorial(3)" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1 2 6 24 120 720 5040 40320 362880 3628800 " + ] + }, + { + "data": { + "text/plain": [ + "3628800" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "factorial(10)" + ] + } + ], + "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.6" + }, + "livereveal": { + "auto_select": "code", + "auto_select_fragment": true, + "scroll": true, + "theme": "serif" + }, + "toc": { + "base_numbering": 1, + "nav_menu": {}, + "number_sections": false, + "sideBar": true, + "skip_h1_title": true, + "title_cell": "Table of Contents", + "title_sidebar": "Contents", + "toc_cell": false, + "toc_position": { + "height": "calc(100% - 180px)", + "left": "10px", + "top": "150px", + "width": "384px" + }, + "toc_section_display": false, + "toc_window_display": false + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/README.md b/README.md index 6843c25..911350d 100644 --- a/README.md +++ b/README.md @@ -98,6 +98,11 @@ Alternatively, the content can be viewed in a web browser - [exercises ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/04_iteration/01_exercises.ipynb) [](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/04_iteration/01_exercises.ipynb) (Towers of Hanoi) + - [content ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/04_iteration/02_content.ipynb) + [](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/04_iteration/02_content.ipynb) + (Looping with `while` & `for`; + Examples: Collatz Conjecture, Factorial, Euclid's Algorithm, & Fibonacci; + Containers vs. Iterables) #### Videos From e9b166a618230ce9c7451dc9caaab46ad849bc11 Mon Sep 17 00:00:00 2001 From: Alexander Hess Date: Thu, 15 Oct 2020 18:54:15 +0200 Subject: [PATCH 4/7] Add initial version of chapter 04, part 3 --- 04_iteration/03_content.ipynb | 991 ++++++++++++++++++++++++++++++++++ README.md | 4 + 2 files changed, 995 insertions(+) create mode 100644 04_iteration/03_content.ipynb diff --git a/04_iteration/03_content.ipynb b/04_iteration/03_content.ipynb new file mode 100644 index 0000000..8cfb19f --- /dev/null +++ b/04_iteration/03_content.ipynb @@ -0,0 +1,991 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "**Note**: Click on \"*Kernel*\" > \"*Restart Kernel and Clear All Outputs*\" in [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) *before* reading this notebook to reset its output. If you cannot run this file on your machine, you may want to open it [in the cloud ](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/04_iteration/03_content.ipynb)." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "# Chapter 4: Recursion & Looping (continued)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "While what we learned about the `for` and `while` statements in the [second part ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/04_iteration/02_content.ipynb) of this chapter suffices to translate any iterative algorithm into code, both come with some syntactic sugar to make life easier for the developer. This last part of the chapter shows how we can further customize the looping logic and introduces as \"trick\" for situations where we cannot come up with a stopping criterion in a `while`-loop." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Stopping Loops prematurely" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "This section introduces additional syntax to customize `for` and `while` statements in our code even further. They are mostly syntactic sugar in that they do not change how a program runs but make its code more readable. We illustrate them for the `for` statement only. However, everything presented in this section also works for the `while` statement." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "### Example: Is the square of a number in `[7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]` greater than `100`?" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "Let's say we have a list of `numbers` and want to check if the square of at least one of its elements is greater than `100`. So, conceptually, we are asking the question if a list of numbers as a whole satisfies a certain condition." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "numbers = [7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "A first naive implementation could look like this: We loop over *every* element in `numbers` and set an **indicator variable** `is_above`, initialized as `False`, to `True` once we encounter an element satisfying the condition.\n", + "\n", + "This implementation is *inefficient* as even if the *first* element in `numbers` has a square greater than `100`, we loop until the last element: This could take a long time for a big list.\n", + "\n", + "Moreover, we must initialize `is_above` *before* the `for`-loop and write an `if`-`else`-logic *after* it to check for the result. The actual business logic is *not* conveyed in a clear way." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "7 11 8 5 3 12 2 6 9 10 1 4 => at least one number satisfies the condition\n" + ] + } + ], + "source": [ + "is_above = False\n", + "\n", + "for number in numbers:\n", + " print(number, end=\" \") # added for didactical purposes\n", + " if number ** 2 > 100:\n", + " is_above = True\n", + "\n", + "if is_above:\n", + " print(\"=> at least one number satisfies the condition\")\n", + "else:\n", + " print(\"=> no number satisfies the condition\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "### The `break` Statement" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "Python provides the `break` statement (cf., [reference ](https://docs.python.org/3/reference/simple_stmts.html#the-break-statement)) that lets us stop a loop prematurely at any iteration. It is yet another means of controlling the flow of execution, and we say that we \"break out of a loop.\"" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "7 11 => at least one number satisfies the condition\n" + ] + } + ], + "source": [ + "is_above = False\n", + "\n", + "for number in numbers:\n", + " print(number, end=\" \") # added for didactical purposes\n", + " if number ** 2 > 100:\n", + " is_above = True\n", + " break\n", + "\n", + "if is_above:\n", + " print(\"=> at least one number satisfies the condition\")\n", + "else:\n", + " print(\"=> no number satisfies the condition\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "This is a computational improvement. However, the code still consists of *three* sections: Some initialization *before* the `for`-loop, the loop itself, and some finalizing logic. We prefer to convey the program's idea in *one* compound statement instead." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "### The `else`-clause" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "To express the logic in a prettier way, we add an `else`-clause at the end of the `for`-loop (cf., [reference ](https://docs.python.org/3/reference/compound_stmts.html#the-for-statement)). The `else`-clause is executed *only if* the `for`-loop is *not* stopped with a `break` statement *prematurely* (i.e., *before* reaching the *last* iteration in the loop). The word \"else\" implies a somewhat unintuitive meaning and may have better been named a `then`-clause. In most use cases, however, the `else`-clause logically goes together with some `if` statement in the loop's body.\n", + "\n", + "Overall, the code's expressive power increases. Not many programming languages support an optional `else`-branching for the `for` and `while` statements, which turns out to be very useful in practice." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "7 11 => at least one number satisfies the condition\n" + ] + } + ], + "source": [ + "for number in numbers:\n", + " print(number, end=\" \") # added for didactical purposes\n", + " if number ** 2 > 100:\n", + " is_above = True\n", + " break\n", + "else:\n", + " is_above = False\n", + "\n", + "if is_above:\n", + " print(\"=> at least one number satisfies the condition\")\n", + "else:\n", + " print(\"=> no number satisfies the condition\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "Lastly, we incorporate the finalizing `if`-`else` logic into the `for`-loop, avoiding the `is_above` variable altogether." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "7 11 => at least one number satisfies the condition\n" + ] + } + ], + "source": [ + "for number in numbers:\n", + " print(number, end=\" \") # added for didactical purposes\n", + " if number ** 2 > 100:\n", + " print(\"=> at least one number satisfies the condition\")\n", + " break\n", + "else:\n", + " print(\"=> no number satisfies the condition\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "Of course, if we choose the number an element's square has to pass to be larger, for example, to `200`, we have to loop over all `numbers`. There is *no way* to optimize this **[linear search ](https://en.wikipedia.org/wiki/Linear_search)** further." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "7 11 8 5 3 12 2 6 9 10 1 4 => no number satisfies the condition\n" + ] + } + ], + "source": [ + "for number in numbers:\n", + " print(number, end=\" \") # added for didactical purposes\n", + " if number ** 2 > 200:\n", + " print(\"=> at least one number satisfies the condition\")\n", + " break\n", + "else:\n", + " print(\"=> no number satisfies the condition\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## A first Glance at the **Map-Filter-Reduce** Paradigm" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "Often, we process some iterable with numeric data, for example, a list of `numbers` as in this book's introductory example in [Chapter 1 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/01_elements/00_content.ipynb#Example:-Averaging-all-even-Numbers-in-a-List) or, more realistically, data from a CSV file with many rows and columns.\n", + "\n", + "Processing numeric data usually comes down to operations that may be grouped into one of the following three categories:\n", + "\n", + "- **mapping**: transform a number according to some functional relationship $y = f(x)$\n", + "- **filtering**: throw away individual numbers (e.g., statistical outliers in a sample)\n", + "- **reducing**: collect individual numbers into summary statistics\n", + "\n", + "We study this **map-filter-reduce** paradigm extensively in [Chapter 8 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/08_mfr/00_content.ipynb) after introducing more advanced data types that are needed to work with \"big\" data.\n", + "\n", + "Here, we focus on *filtering out* some numbers in a `for`-loop." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "### Example: A simple Filter" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "Calculate the sum of all even numbers in `[7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]` after squaring them and adding `1` to the squares:\n", + "\n", + "- \"*all*\" => **loop** over an iterable\n", + "- \"*even*\" => **filter** out the odd numbers\n", + "- \"*square and add $1$*\" => apply the **map** $y = f(x) = x^2 + 1$\n", + "- \"*sum*\" => **reduce** the remaining and mapped numbers to their sum" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "numbers = [7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "8 -> 65 12 -> 145 2 -> 5 6 -> 37 10 -> 101 4 -> 17 " + ] + }, + { + "data": { + "text/plain": [ + "370" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "total = 0\n", + "\n", + "for number in numbers:\n", + " if number % 2 == 0: # only keep even numbers\n", + " square = (number ** 2) + 1\n", + " print(number, \"->\", square, end=\" \") # added for didactical purposes\n", + " total += square\n", + "\n", + "total" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "The above code is easy to read as it involves only two levels of indentation.\n", + "\n", + "In general, code gets harder to comprehend the more **horizontal space** it occupies. It is commonly considered good practice to grow a program **vertically** rather than horizontally. Code compliant with [PEP 8 ](https://www.python.org/dev/peps/pep-0008/#maximum-line-length) requires us to use *at most* 79 characters in a line!\n", + "\n", + "Consider the next example, whose implementation in code already starts to look unbalanced." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "### Example: Several Filters" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "Calculate the sum of every third and even number in `[7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]` after squaring them and adding `1` to the squares:\n", + "\n", + "- \"*every*\" => **loop** over an iterable\n", + "- \"*third*\" => **filter** out all numbers except every third\n", + "- \"*even*\" => **filter** out the odd numbers\n", + "- \"*square and add $1$*\" => apply the **map** $y = f(x) = x^2 + 1$\n", + "- \"*sum*\" => **reduce** the remaining and mapped numbers to their sum" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "8 -> 65 12 -> 145 4 -> 17 " + ] + }, + { + "data": { + "text/plain": [ + "227" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "total = 0\n", + "\n", + "for i, number in enumerate(numbers, start=1):\n", + " if i % 3 == 0: # only keep every third number\n", + " if number % 2 == 0: # only keep even numbers\n", + " square = (number ** 2) + 1\n", + " print(number, \"->\", square, end=\" \") # added for didactical purposes \n", + " total += square\n", + "\n", + "total" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "With already three levels of indentation, less horizontal space is available for the actual code block. Of course, one could flatten the two `if` statements with the logical `and` operator, as shown in [Chapter 3 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/03_conditionals/00_content.ipynb#The-if-Statement). Then, however, we trade off horizontal space against a more \"complex\" `if` logic, and this is *not* a real improvement." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "### The `continue` Statement" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "A Pythonista would instead make use of the `continue` statement (cf., [reference ](https://docs.python.org/3/reference/simple_stmts.html#the-continue-statement)) that causes a loop to jump into the next iteration skipping the rest of the code block.\n", + "\n", + "The revised code fragment below occupies more vertical space and less horizontal space: A *good* trade-off.\n", + "\n", + "One caveat is that we need to negate the conditions in the `if` statements. Conceptually, we are now filtering \"out\" and not \"in.\"" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "8 -> 65 12 -> 145 4 -> 17 " + ] + }, + { + "data": { + "text/plain": [ + "227" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "total = 0\n", + "\n", + "for i, number in enumerate(numbers, start=1):\n", + " if i % 3 != 0: # only keep every third number\n", + " continue\n", + " elif number % 2 != 0: # only keep even numbers\n", + " continue\n", + "\n", + " square = (number ** 2) + 1\n", + " print(number, \"->\", square, end=\" \") # added for didactical purposes \n", + " total += square\n", + "\n", + "total" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "This is yet another illustration of why programming is an art. The two preceding code cells do the *same* with *identical* time complexity. However, the latter is arguably easier to read for a human, even more so when the business logic grows beyond two filters." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Indefinite Loops" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "Sometimes we find ourselves in situations where we *cannot* know ahead of time how often or until which point in time a code block is to be executed." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "### Example: Guessing a Coin Toss" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "Let's consider a game where we randomly choose a variable to be either \"Heads\" or \"Tails\" and the user of our program has to guess it.\n", + "\n", + "Python provides the built-in [input() ](https://docs.python.org/3/library/functions.html#input) function that prints a message to the user, called the **prompt**, and reads in what was typed in response as a `str` object. We use it to process a user's \"unreliable\" input to our program (i.e., a user might type in some invalid response). Further, we use the [random() ](https://docs.python.org/3/library/random.html#random.random) function in the [random ](https://docs.python.org/3/library/random.html) module to model the coin toss.\n", + "\n", + "A popular pattern to approach such **indefinite loops** is to go with a `while True` statement, which on its own would cause Python to enter into an infinite loop. Then, once a particular event occurs, we `break` out of the loop.\n", + "\n", + "Let's look at a first and naive implementation." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "import random" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [], + "source": [ + "random.seed(42)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "code_folding": [], + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "name": "stdin", + "output_type": "stream", + "text": [ + "Guess if the coin comes up as heads or tails: heads\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Ooops, it was tails\n" + ] + }, + { + "name": "stdin", + "output_type": "stream", + "text": [ + "Guess if the coin comes up as heads or tails: heads\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Yes, it was heads\n" + ] + } + ], + "source": [ + "while True:\n", + " guess = input(\"Guess if the coin comes up as heads or tails: \")\n", + "\n", + " if random.random() < 0.5:\n", + " if guess == \"heads\":\n", + " print(\"Yes, it was heads\")\n", + " break\n", + " else:\n", + " print(\"Ooops, it was heads\")\n", + " else:\n", + " if guess == \"tails\":\n", + " print(\"Yes, it was tails\")\n", + " break\n", + " else:\n", + " print(\"Ooops, it was tails\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "This version exhibits two *severe* issues where we should improve on:\n", + "\n", + "1. If a user enters *anything* other than `\"heads\"` or `\"tails\"`, for example, `\"Heads\"` or `\"Tails\"`, the program keeps running *without* the user knowing about the mistake!\n", + "2. The code *intermingles* the coin tossing with the processing of the user's input: Mixing *unrelated* business logic in the *same* code block makes a program harder to read and, more importantly, maintain in the long run." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "### Example: Guessing a Coin Toss (revisited)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "Let's refactor the code and make it *modular*.\n", + "\n", + "First, we divide the business logic into two functions `get_guess()` and `toss_coin()` that are controlled from within a `while`-loop.\n", + "\n", + "`get_guess()` not only reads in the user's input but also implements a simple input validation pattern in that the [strip() ](https://docs.python.org/3/library/stdtypes.html?highlight=__contains__#str.strip) and [lower() ](https://docs.python.org/3/library/stdtypes.html?highlight=__contains__#str.lower) methods remove preceding and trailing whitespace and lower case the input ensuring that the user may spell the input in any possible way (e.g., all upper or lower case). Also, `get_guess()` checks if the user entered one of the two valid options. If so, it returns either `\"heads\"` or `\"tails\"`; if not, it returns `None`." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "def get_guess():\n", + " \"\"\"Process the user's input.\n", + " \n", + " Returns:\n", + " guess (str / NoneType): either \"heads\" or \"tails\"\n", + " if the input can be parsed and None otherwise\n", + " \"\"\"\n", + " guess = input(\"Guess if the coin comes up as heads or tails: \")\n", + " # handle frequent cases of \"misspelled\" user input\n", + " guess = guess.strip().lower()\n", + "\n", + " if guess in [\"heads\", \"tails\"]:\n", + " return guess\n", + " return None" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "`toss_coin()` models a fair coin toss when called with default arguments." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "def toss_coin(p_heads=0.5):\n", + " \"\"\"Simulate the tossing of a coin.\n", + "\n", + " Args:\n", + " p_heads (optional, float): probability that the coin comes up \"heads\";\n", + " defaults to 0.5 resembling a fair coin\n", + "\n", + " Returns:\n", + " side_on_top (str): \"heads\" or \"tails\"\n", + " \"\"\"\n", + " if random.random() < p_heads:\n", + " return \"heads\"\n", + " return \"tails\"" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "Second, we rewrite the `if`-`else`-logic to handle the case where `get_guess()` returns `None` explicitly: Whenever the user enters something invalid, a warning is shown, and another try is granted. We use the `is` operator and not the `==` operator as `None` is a singleton object.\n", + "\n", + "The `while`-loop takes on the role of **glue code** that manages how other parts of the program interact with each other." + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [], + "source": [ + "random.seed(42)" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "name": "stdin", + "output_type": "stream", + "text": [ + "Guess if the coin comes up as heads or tails: invalid\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Make sure to enter your guess correctly!\n" + ] + }, + { + "name": "stdin", + "output_type": "stream", + "text": [ + "Guess if the coin comes up as heads or tails: Heads\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Yes, it was heads\n" + ] + } + ], + "source": [ + "while True:\n", + " guess = get_guess()\n", + " result = toss_coin()\n", + "\n", + " if guess is None:\n", + " print(\"Make sure to enter your guess correctly!\")\n", + " elif guess == result:\n", + " print(\"Yes, it was\", result)\n", + " break\n", + " else:\n", + " print(\"Ooops, it was\", result)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "Now, the program's business logic is expressed in a clearer way. More importantly, we can now change it more easily. For example, we could make the `toss_coin()` function base the tossing on a probability distribution other than the uniform (i.e., replace the [random.random() ](https://docs.python.org/3/library/random.html#random.random) function with another one). In general, modular architecture leads to improved software maintenance." + ] + } + ], + "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.6" + }, + "livereveal": { + "auto_select": "code", + "auto_select_fragment": true, + "scroll": true, + "theme": "serif" + }, + "toc": { + "base_numbering": 1, + "nav_menu": {}, + "number_sections": false, + "sideBar": true, + "skip_h1_title": true, + "title_cell": "Table of Contents", + "title_sidebar": "Contents", + "toc_cell": false, + "toc_position": { + "height": "calc(100% - 180px)", + "left": "10px", + "top": "150px", + "width": "384px" + }, + "toc_section_display": false, + "toc_window_display": false + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/README.md b/README.md index 911350d..2e7f606 100644 --- a/README.md +++ b/README.md @@ -103,6 +103,10 @@ Alternatively, the content can be viewed in a web browser (Looping with `while` & `for`; Examples: Collatz Conjecture, Factorial, Euclid's Algorithm, & Fibonacci; Containers vs. Iterables) + - [content ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/04_iteration/03_content.ipynb) + [](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/04_iteration/03_content.ipynb) + (Customizing Loops with `break` and `continue`; + Indefinite Loops) #### Videos From b73df81315e7e1d52fede4cdb92efae9261cccc3 Mon Sep 17 00:00:00 2001 From: Alexander Hess Date: Thu, 15 Oct 2020 18:56:35 +0200 Subject: [PATCH 5/7] Add initial version of chapter 04's exercises, part 2 --- 04_iteration/04_exercises.ipynb | 403 ++++++++++++++++++++++++++++++++ README.md | 3 + 2 files changed, 406 insertions(+) create mode 100644 04_iteration/04_exercises.ipynb diff --git a/04_iteration/04_exercises.ipynb b/04_iteration/04_exercises.ipynb new file mode 100644 index 0000000..04654bc --- /dev/null +++ b/04_iteration/04_exercises.ipynb @@ -0,0 +1,403 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Note**: Click on \"*Kernel*\" > \"*Restart Kernel and Run All*\" in [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) *after* finishing the exercises to ensure that your solution runs top to bottom *without* any errors. If you cannot run this file on your machine, you may want to open it [in the cloud ](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/04_iteration/04_exercises.ipynb)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Chapter 4: Recursion & Looping (Coding Exercises)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The exercises below assume that you have read the [third part ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/04_iteration/03_content.ipynb) of Chapter 4.\n", + "\n", + "The `...`'s in the code cells indicate where you need to fill in code snippets. The number of `...`'s within a code cell give you a rough idea of how many lines of code are needed to solve the task. You should not need to create any additional code cells for your final solution. However, you may want to use temporary code cells to try out some ideas." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Throwing Dice" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In this exercise, you will model the throwing of dice within the context of a guessing game similar to the one shown in the \"*Example: Guessing a Coin Toss*\" section in [Chapter 4 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/04_iteration/03_content.ipynb#Example:-Guessing-a-Coin-Toss).\n", + "\n", + "As the game involves randomness, we import the [random ](https://docs.python.org/3/library/random.html) module from the [standard library ](https://docs.python.org/3/library/index.html). To follow best practices, we set the random seed as well." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import random" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "random.seed(42)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "A die has six sides that we labeled with integers `1` to `6` in this exercise. For a fair die, the probability for each side is the same.\n", + "\n", + "**Q1**: Model a `fair_die` as a `list` object!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fair_die = ..." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Q2**: What function from the [random ](https://docs.python.org/3/library/random.html) module that we have seen already is useful for modeling a single throw of the `fair_die`? Write a simple expression (i.e., one function call) that draws one of the equally likely sides! Execute the cell a couple of times to \"see\" the probability distribution!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "..." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's check if the `fair_die` is indeed fair. To do so, we create a little numerical experiment and throw the `fair_die` `100000` times. We track the six different outcomes in a `list` object called `throws` that we initialize with all `0`s for each outcome.\n", + "\n", + "**Q3**: Complete the `for`-loop below such that it runs `100000` times! In the body, use your answer to **Q2** to simulate a single throw of the `fair_die` and update the corresponding count in `throws`!\n", + "\n", + "Hints: You need to use the indexing operator `[]` and calculate an `index` in each iteration of the loop. Do do not actually need the target variable provided by the `for`-loop and may want to indicate that with an underscore `_`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "throws = [0, 0, 0, 0, 0, 0]\n", + "\n", + "for ... in ...:\n", + " ...\n", + " ...\n", + " ...\n", + "\n", + "throws" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "`throws` contains the simulation results as absolute counts.\n", + "\n", + "**Q4**: Complete the `for`-loop below to convert the counts in `throws` to relative frequencies stored in a `list` called `frequencies`! Round the frequencies to three decimals with the built-in [round() ](https://docs.python.org/3/library/functions.html#round) function!\n", + "\n", + "Hints: Initialize `frequencies` just as `throws` above. How many iterations does the `for`-loop have? `6` or `100000`? You may want to obtain an `index` variable with the [enumerate() ](https://docs.python.org/3/library/functions.html#enumerate) built-in." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "frequencies = [0, 0, 0, 0, 0, 0]\n", + "\n", + "for ... in ...:\n", + " ...\n", + "\n", + "frequencies" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Q5**: How could we adapt the `list` object used above to model an `unfair_die` where `1` is as likely as `2`, `2` is twice as likely as `3`, and `3` is twice as likely as `4`, `5`, or `6`, who are all equally likely?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "unfair_die = ..." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Q6**: Copy your solution to **Q2** for the `unfair_die`! Execute the cell a couple of times to \"see\" the probability distribution!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "..." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Q7**: Copy and adapt your solutions to **Q3** and **Q4** to calculate the `frequencies` for the `unfair_die`!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "throws = [0, 0, 0, 0, 0, 0]\n", + "frequencies = [0, 0, 0, 0, 0, 0]\n", + "\n", + "for ... in ...:\n", + " ...\n", + " ...\n", + " ...\n", + "\n", + "for ... in ...:\n", + " ...\n", + "\n", + "frequencies" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Q8**: The built-in [input() ](https://docs.python.org/3/library/functions.html#input) allows us to ask the user to enter a `guess`. What is the data type of the object returned by [input() ](https://docs.python.org/3/library/functions.html#input)? Assume the user enters the `guess` as a number (i.e., \"1\", \"2\", ...) and not as a text (e.g., \"one\")." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "guess = input(\"Guess the side of the die: \")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "guess" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "..." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Q9**: Use a built-in constructor to cast `guess` as an `int` object!\n", + "\n", + "Hint: Simply wrap `guess` or `input(\"Guess the side of the die: \")` with the constructor you choose." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "..." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Q10**: What type of error is raised if `guess` cannot be cast as an `int` object?" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " < your answer >" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Q11**: Write a `try` statement that catches the type of error (i.e., your answer to **Q10**) raised if the user's input cannot be cast as an `int` object! Print out some nice error message notifying the user of the bad input!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " ...\n", + "except ...:\n", + " ..." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Q12**: Write a function `get_guess()` that takes a user's input and checks if it is a valid side of the die! The function should *return* either an `int` object between `1` and `6` or `None` if the user enters something invalid.\n", + "\n", + "Hints: You may want to re-use the `try` statement from **Q11**. Instead of printing out an error message, you can also `return` directly from the `except`-clause (i.e., early exit) with `None`. So, the user can make *two* kinds of input errors and maybe you want to model that with two *distinct* `return None` statements. Also, you may want to allow the user to enter leading and trailing whitespace that gets removed without an error message." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def get_guess():\n", + " \"\"\"Process the user's input.\n", + " \n", + " Returns:\n", + " guess (int / NoneType): either 1, 2, 3, 4, 5 or 6\n", + " if the input can be parsed and None otherwise\n", + " \"\"\"\n", + " ...\n", + "\n", + " # Check if the user entered an integer.\n", + " ...\n", + " ...\n", + " ...\n", + " ...\n", + "\n", + " # Check if the user entered a valid side.\n", + " ...\n", + " ...\n", + " ..." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Q13** Test your function for all *three* cases!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "get_guess()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Q14**: Write an *indefinite* loop where in each iteration a `fair_die` is thrown and the user makes a guess! Print out an error message if the user does not enter something that can be understood as a number between `1` and `6`! The game should continue until the user makes a correct guess." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "...\n", + "...\n", + "...\n", + "\n", + "...\n", + "...\n", + "...\n", + "...\n", + "...\n", + "...\n", + "..." + ] + } + ], + "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.6" + }, + "toc": { + "base_numbering": 1, + "nav_menu": {}, + "number_sections": false, + "sideBar": true, + "skip_h1_title": true, + "title_cell": "Table of Contents", + "title_sidebar": "Contents", + "toc_cell": false, + "toc_position": {}, + "toc_section_display": false, + "toc_window_display": false + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/README.md b/README.md index 2e7f606..209bbbc 100644 --- a/README.md +++ b/README.md @@ -107,6 +107,9 @@ Alternatively, the content can be viewed in a web browser [](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/04_iteration/03_content.ipynb) (Customizing Loops with `break` and `continue`; Indefinite Loops) + - [exercises ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/04_iteration/04_exercises.ipynb) + [](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/04_iteration/04_exercises.ipynb) + (Throwing Dice) #### Videos From 5958b386876f690e3d858f9448f0ad709bc77645 Mon Sep 17 00:00:00 2001 From: Alexander Hess Date: Thu, 15 Oct 2020 18:58:27 +0200 Subject: [PATCH 6/7] Add initial version of chapter 04's summary --- 04_iteration/05_summary.ipynb | 79 +++++++++++++++++++++++++++++++++++ README.md | 1 + 2 files changed, 80 insertions(+) create mode 100644 04_iteration/05_summary.ipynb diff --git a/04_iteration/05_summary.ipynb b/04_iteration/05_summary.ipynb new file mode 100644 index 0000000..981bfec --- /dev/null +++ b/04_iteration/05_summary.ipynb @@ -0,0 +1,79 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "# Chapter 4: Recursion & Looping (TL;DR)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "**Iteration** is about **running blocks of code repeatedly**.\n", + "\n", + "There are two redundant approaches to achieving that.\n", + "\n", + "First, we combine functions that call themselves with conditional statements. This concept is known as **recursion** and suffices to control the flow of execution in *every* way we desire. For a beginner, this approach of **backward** reasoning might not be intuitive, but it turns out to be a handy tool to have in one's toolbox.\n", + "\n", + "Second, the `while` and `for` statements are alternative and potentially more intuitive ways to express iteration as they correspond to a **forward** reasoning. The `for` statement is **syntactic sugar** that allows rewriting common occurrences of the `while` statement concisely. Python provides the `break` and `continue` statements as well as an optional `else`-clause that make working with the `for` and `while` statements even more convenient.\n", + "\n", + "**Iterables** are any **concrete data types** that support being looped over, for example, with the `for` statement. The idea behind iterables is an **abstract concept** that may or may not be implemented by any given concrete data type. For example, both `list` and `range` objects can be looped over. The `list` type is also a **container** as any given `list` objects \"contains\" references to other objects in memory. On the contrary, the `range` type does not reference any other object but instead creates *new* `int` objects \"on the fly\" (i.e., when being looped over)." + ] + } + ], + "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.6" + }, + "livereveal": { + "auto_select": "code", + "auto_select_fragment": true, + "scroll": true, + "theme": "serif" + }, + "toc": { + "base_numbering": 1, + "nav_menu": {}, + "number_sections": false, + "sideBar": true, + "skip_h1_title": true, + "title_cell": "Table of Contents", + "title_sidebar": "Contents", + "toc_cell": false, + "toc_position": { + "height": "calc(100% - 180px)", + "left": "10px", + "top": "150px", + "width": "384px" + }, + "toc_section_display": false, + "toc_window_display": false + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/README.md b/README.md index 209bbbc..f431c9a 100644 --- a/README.md +++ b/README.md @@ -110,6 +110,7 @@ Alternatively, the content can be viewed in a web browser - [exercises ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/04_iteration/04_exercises.ipynb) [](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/04_iteration/04_exercises.ipynb) (Throwing Dice) + - [summary ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/04_iteration/05_summary.ipynb) #### Videos From f557daee31c5f3fe3a1fd0970ca65d98b00d919d Mon Sep 17 00:00:00 2001 From: Alexander Hess Date: Thu, 15 Oct 2020 19:00:14 +0200 Subject: [PATCH 7/7] Add initial version of chapter 04's review --- 04_iteration/06_review.ipynb | 268 +++++++++++++++++++++++++++++++++++ README.md | 1 + 2 files changed, 269 insertions(+) create mode 100644 04_iteration/06_review.ipynb diff --git a/04_iteration/06_review.ipynb b/04_iteration/06_review.ipynb new file mode 100644 index 0000000..b40647b --- /dev/null +++ b/04_iteration/06_review.ipynb @@ -0,0 +1,268 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Chapter 4: Recursion & Looping (Review Questions)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The questions below assume that you have read the [first ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/04_iteration/00_content.ipynb), [second ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/04_iteration/02_content.ipynb), and the [third ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/04_iteration/03_content.ipynb) part of Chapter 4.\n", + "\n", + "Be concise in your answers! Most questions can be answered in *one* sentence." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Essay Questions " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Q1**: Solving a problem by **recursion** is not only popular in computer science and math. Name some examples from the fields of business or economics where problems are also solved in a **backward** fashion!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " < your answer >" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Q2**: Explain what **duck typing** means! Why can it cause problems? Why is it [not a bug but a feature](https://www.urbandictionary.com/define.php?term=It%27s%20not%20a%20bug%2C%20it%27s%20a%20feature)?" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " < your answer >" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Q3**: What is **syntactic sugar**?" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " < your answer >" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Q4**: Describe in your own words why the **recursive** version of `fibonacci()`, the \"Easy at first Glance\" example in the chapter, is computationally **inefficient**! Why does the **iterative** version of `fibonacci()`, the \"Hard at first Glance\" example, run so much faster?" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " < your answer >" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Q5**: What is the conceptual difference between a **container** and a **list**?" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " < your answer >" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Q6**: What is a good use case for the `for`-loop's optional `else`-clause?" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " < your answer >" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## True / False Questions" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Motivate your answer with *one short* sentence!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Q7**: When a **recursion** does **not** reach the base case, this is an example of the **early exit** strategy." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " < your answer >" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Q8**: Any programming language **without** looping constructs like the `for` or `while` statements is **not** Turing complete." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " < your answer >" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Q9**: A **recursive** formulation is the same as a **circular** one: The terms are **synonyms**." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " < your answer >" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Q10**: Formulating a computational problem as a **recursion** results in an **efficient** implementation." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " < your answer >" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Q11**: Whereas a **recursion** may accidentally result in a **never-ending** program, `while`-loops and `for`-loops are guaranteed to **terminate**." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " < your answer >" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Q12**: Before writing **any** kind of **loop**, we **always** need to think about a **stopping criterion** ahead of time." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " < your answer >" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Q13**: **Container** types such as `list` objects are characterized by their **support** for **being looped over**, for example as in:" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "```python\n", + "for element in container:\n", + " # do something for every element\n", + " ...\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " < your answer >" + ] + } + ], + "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.6" + }, + "toc": { + "base_numbering": 1, + "nav_menu": {}, + "number_sections": false, + "sideBar": true, + "skip_h1_title": true, + "title_cell": "Table of Contents", + "title_sidebar": "Contents", + "toc_cell": false, + "toc_position": {}, + "toc_section_display": false, + "toc_window_display": false + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/README.md b/README.md index f431c9a..bb5114f 100644 --- a/README.md +++ b/README.md @@ -111,6 +111,7 @@ Alternatively, the content can be viewed in a web browser [](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/04_iteration/04_exercises.ipynb) (Throwing Dice) - [summary ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/04_iteration/05_summary.ipynb) + - [review questions ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/04_iteration/06_review.ipynb) #### Videos