{ "cells": [ { "cell_type": "markdown", "id": "starting-portfolio", "metadata": {}, "source": [ "# Recursion" ] }, { "cell_type": "markdown", "id": "further-brighton", "metadata": {}, "source": [ "A recursive algorithm is an algorithm that calls itself. You need a base case so you don't get stuck in an infinite loop." ] }, { "cell_type": "markdown", "id": "sunrise-cyprus", "metadata": {}, "source": [ "Example: suppose we want to calculate the quantity $n! = n(n-1)(n-2)\\cdots 3 \\cdot 2 \\cdot 1$." ] }, { "cell_type": "markdown", "id": "18459a42", "metadata": {}, "source": [ "5! = 5 * 4 * 3 * 2 * 1 = 120" ] }, { "cell_type": "markdown", "id": "gorgeous-girlfriend", "metadata": {}, "source": [ "We'll use the fact that $n! = n \\cdot (n-1)!$." ] }, { "cell_type": "code", "execution_count": 1, "id": "metallic-psychiatry", "metadata": {}, "outputs": [], "source": [ "# What's wrong with this function?\n", "def factorial(n):\n", " return n * factorial(n-1)" ] }, { "cell_type": "code", "execution_count": 2, "id": "appropriate-moore", "metadata": {}, "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)", "Cell \u001b[0;32mIn[2], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mfactorial\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m3\u001b[39;49m\u001b[43m)\u001b[49m\n", "Cell \u001b[0;32mIn[1], line 3\u001b[0m, in \u001b[0;36mfactorial\u001b[0;34m(n)\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mfactorial\u001b[39m(n):\n\u001b[0;32m----> 3\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m n \u001b[38;5;241m*\u001b[39m \u001b[43mfactorial\u001b[49m\u001b[43m(\u001b[49m\u001b[43mn\u001b[49m\u001b[38;5;241;43m-\u001b[39;49m\u001b[38;5;241;43m1\u001b[39;49m\u001b[43m)\u001b[49m\n", "Cell \u001b[0;32mIn[1], line 3\u001b[0m, in \u001b[0;36mfactorial\u001b[0;34m(n)\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mfactorial\u001b[39m(n):\n\u001b[0;32m----> 3\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m n \u001b[38;5;241m*\u001b[39m \u001b[43mfactorial\u001b[49m\u001b[43m(\u001b[49m\u001b[43mn\u001b[49m\u001b[38;5;241;43m-\u001b[39;49m\u001b[38;5;241;43m1\u001b[39;49m\u001b[43m)\u001b[49m\n", " \u001b[0;31m[... skipping similar frames: factorial at line 3 (2970 times)]\u001b[0m\n", "Cell \u001b[0;32mIn[1], line 3\u001b[0m, in \u001b[0;36mfactorial\u001b[0;34m(n)\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mfactorial\u001b[39m(n):\n\u001b[0;32m----> 3\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m n \u001b[38;5;241m*\u001b[39m \u001b[43mfactorial\u001b[49m\u001b[43m(\u001b[49m\u001b[43mn\u001b[49m\u001b[38;5;241;43m-\u001b[39;49m\u001b[38;5;241;43m1\u001b[39;49m\u001b[43m)\u001b[49m\n", "\u001b[0;31mRecursionError\u001b[0m: maximum recursion depth exceeded" ] } ], "source": [ "factorial(3)" ] }, { "cell_type": "markdown", "id": "31f6174b", "metadata": {}, "source": [ "What calls are happening?\n", "```py\n", "```" ] }, { "cell_type": "code", "execution_count": null, "id": "dbbe172d", "metadata": {}, "outputs": [], "source": [ "# What's wrong with this function?\n", "def factorial(n):\n", " return n * factorial(n-1)" ] }, { "cell_type": "markdown", "id": "5ba3a205", "metadata": {}, "source": [ "```py\n", "factorial(3)\n", " -> 3 * factorial(2)\n", " -> 3 * 2 * factorial(1)\n", " -> 3 * 2 * 1 * factorial(0)\n", " -> 3 * 2 * 1 * 0 * factorial(-1)\n", " -> infinite recursion\n", "```" ] }, { "cell_type": "code", "execution_count": 14, "id": "failing-lounge", "metadata": {}, "outputs": [], "source": [ "# We need a base case!\n", "def factorial(n):\n", " assert n >= 0 and isinstance(n, int), \"invalid input into factorial\"\n", " if n == 1:\n", " # factorial(1) = 1\n", " return 1\n", " return n * factorial(n-1)" ] }, { "cell_type": "code", "execution_count": 15, "id": "acute-delicious", "metadata": {}, "outputs": [ { "ename": "AssertionError", "evalue": "invalid input into factorial", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mAssertionError\u001b[0m Traceback (most recent call last)", "Cell \u001b[0;32mIn[15], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mfactorial\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m3.5\u001b[39;49m\u001b[43m)\u001b[49m\n", "Cell \u001b[0;32mIn[14], line 3\u001b[0m, in \u001b[0;36mfactorial\u001b[0;34m(n)\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mfactorial\u001b[39m(n):\n\u001b[0;32m----> 3\u001b[0m \u001b[38;5;28;01massert\u001b[39;00m n \u001b[38;5;241m>\u001b[39m\u001b[38;5;241m=\u001b[39m \u001b[38;5;241m0\u001b[39m \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(n, \u001b[38;5;28mint\u001b[39m), \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124minvalid input into factorial\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 4\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m n \u001b[38;5;241m==\u001b[39m \u001b[38;5;241m1\u001b[39m:\n\u001b[1;32m 5\u001b[0m \u001b[38;5;66;03m# factorial(1) = 1\u001b[39;00m\n\u001b[1;32m 6\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;241m1\u001b[39m\n", "\u001b[0;31mAssertionError\u001b[0m: invalid input into factorial" ] } ], "source": [ "factorial(3.5)" ] }, { "cell_type": "markdown", "id": "municipal-phoenix", "metadata": {}, "source": [ "```py\n", "factorial(5)\n", "5 * factorial(4)\n", "5 * (4 * factorial(3))\n", "5 * (4 * (3 * factorial(2)))\n", "5 * (4 * (3 * (2 * factorial(1))))\n", "5 * (4 * (3 * (2 * 1)))\n", "```" ] }, { "cell_type": "code", "execution_count": 9, "id": "functional-pointer", "metadata": {}, "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)", "Cell \u001b[0;32mIn[9], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mfactorial\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m-\u001b[39;49m\u001b[38;5;241;43m1\u001b[39;49m\u001b[43m)\u001b[49m\n", "Cell \u001b[0;32mIn[3], line 6\u001b[0m, in \u001b[0;36mfactorial\u001b[0;34m(n)\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m n \u001b[38;5;241m==\u001b[39m \u001b[38;5;241m1\u001b[39m:\n\u001b[1;32m 4\u001b[0m \u001b[38;5;66;03m# factorial(1) = 1\u001b[39;00m\n\u001b[1;32m 5\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;241m1\u001b[39m\n\u001b[0;32m----> 6\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m n \u001b[38;5;241m*\u001b[39m \u001b[43mfactorial\u001b[49m\u001b[43m(\u001b[49m\u001b[43mn\u001b[49m\u001b[38;5;241;43m-\u001b[39;49m\u001b[38;5;241;43m1\u001b[39;49m\u001b[43m)\u001b[49m\n", "Cell \u001b[0;32mIn[3], line 6\u001b[0m, in \u001b[0;36mfactorial\u001b[0;34m(n)\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m n \u001b[38;5;241m==\u001b[39m \u001b[38;5;241m1\u001b[39m:\n\u001b[1;32m 4\u001b[0m \u001b[38;5;66;03m# factorial(1) = 1\u001b[39;00m\n\u001b[1;32m 5\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;241m1\u001b[39m\n\u001b[0;32m----> 6\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m n \u001b[38;5;241m*\u001b[39m \u001b[43mfactorial\u001b[49m\u001b[43m(\u001b[49m\u001b[43mn\u001b[49m\u001b[38;5;241;43m-\u001b[39;49m\u001b[38;5;241;43m1\u001b[39;49m\u001b[43m)\u001b[49m\n", " \u001b[0;31m[... skipping similar frames: factorial at line 6 (2971 times)]\u001b[0m\n", "Cell \u001b[0;32mIn[3], line 6\u001b[0m, in \u001b[0;36mfactorial\u001b[0;34m(n)\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m n \u001b[38;5;241m==\u001b[39m \u001b[38;5;241m1\u001b[39m:\n\u001b[1;32m 4\u001b[0m \u001b[38;5;66;03m# factorial(1) = 1\u001b[39;00m\n\u001b[1;32m 5\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;241m1\u001b[39m\n\u001b[0;32m----> 6\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m n \u001b[38;5;241m*\u001b[39m \u001b[43mfactorial\u001b[49m\u001b[43m(\u001b[49m\u001b[43mn\u001b[49m\u001b[38;5;241;43m-\u001b[39;49m\u001b[38;5;241;43m1\u001b[39;49m\u001b[43m)\u001b[49m\n", "\u001b[0;31mRecursionError\u001b[0m: maximum recursion depth exceeded" ] } ], "source": [ "factorial(-1)" ] }, { "cell_type": "code", "execution_count": null, "id": "chinese-applicant", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.1" } }, "nbformat": 4, "nbformat_minor": 5 }