From d42f25159069460549abf87ea639a21b96ab3865 Mon Sep 17 00:00:00 2001 From: fbezir Date: Thu, 18 Mar 2021 12:38:45 +0300 Subject: [PATCH] Delete CE302-Week3-Exercise.ipynb --- CE302-Week3-Exercise.ipynb | 658 ------------------------------------- 1 file changed, 658 deletions(-) delete mode 100644 CE302-Week3-Exercise.ipynb diff --git a/CE302-Week3-Exercise.ipynb b/CE302-Week3-Exercise.ipynb deleted file mode 100644 index 0b87f1f..0000000 --- a/CE302-Week3-Exercise.ipynb +++ /dev/null @@ -1,658 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Function Exercises\n", - "### Source:https://pythonnumericalmethods.berkeley.edu/notebooks/chapter03.01-Function-Basics.html" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "![](Figures/Shortcuts.png)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Verify that len is a built-in function using the type function.\n", - "type(len)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# TRY it! Verify that np.linspace is a function using the type function. \n", - "# And find how to use the function using the question mark.\n", - "import numpy as np\n", - "\n", - "type(np.linspace)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Define your own function\n", - "We can define our own functions. A function can be specified in several ways. Here we will introduce the most common way to define a function which can be specified using the keyword def, as showing in the following:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def function_name(argument_1, argument_2, ...):\n", - " '''\n", - " Descriptive String\n", - " '''\n", - " # comments about the statements\n", - " function_statements \n", - " \n", - " return output_parameters (optional)" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "# TRY IT! Define a function named my_adder to take in 3 numbers and sum them.\n", - "\n", - "def my_adder(a, b, c):\n", - " \"\"\"\n", - " function to sum the 3 numbers\n", - " Input: 3 numbers a, b, c\n", - " Output: the sum of a, b, and c\n", - " author:\n", - " date:\n", - " \"\"\"\n", - " \n", - " # this is the summation\n", - " out = a + b + c\n", - " \n", - " return out\n", - "\n", - "# Note That: Indentation is Important" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Help on function my_adder in module __main__:\n", - "\n", - "my_adder(a, b, c)\n", - " function to sum the 3 numbers\n", - " Input: 3 numbers a, b, c\n", - " Output: the sum of a, b, and c\n", - " author:\n", - " date:\n", - "\n" - ] - } - ], - "source": [ - "help(my_adder)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Find the error!\n", - "d = my_adder('1', 2, 3)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Python functions can have multiple output parameters. When calling a function with **multiple output parameters**, you can place the multiple variables you want assigned separated by commas. The function essentially will return the multiple result parameters in a *tuple*, therefore, you could unpack the returned tuple. Consider the following function (note that it has multiple output parameters):" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def my_trig_sum(a, b):\n", - " \"\"\"\n", - " function to demo return multiple\n", - " author\n", - " date\n", - " \"\"\"\n", - " out1 = np.sin(a) + np.cos(b)\n", - " out2 = np.sin(b) + np.cos(a)\n", - " return out1, out2, [out1, out2]\n", - "\n", - "# here is the unpacking part\n", - "c, d, e = my_trig_sum(2, 3)\n", - "print(f\"c ={c}, d={d}, e={e}\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# EXAMPLE: Run the following function with and without an input.\n", - "\n", - "def print_greeting(day = 'Monday', name = 'Qingkai'):\n", - " print(f'Greetings, {name}, today is {day}')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Warning: \n", - "\n", - "We can see that, if we give a value to the argument when we define the function, this value will be the default value of the function. If the user doesn’t provide an input to this argument, then this default value will be used during calling of the function. Besides, the order of the argument is not important when calling the function if you provide the name of the argument. Look at below:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "print_greeting(name = 'Alex')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Local Variables and Global Variables\n", - "\n", - "Chapter 2 introduced the idea of the memory associated with the notebook where variables created in the notebook are stored. A function also has its own memory block that is reserved for variables created within that function. This block of memory is not shared with the whole notebook memory block. Therefore, a variable with a given name can be assigned within a fucntion without changing a variable with the same name outside of the function. The memory block associated with the function is opened every time a function is used.\n", - "\n", - "\n", - "TRY IT! \n", - "\n", - "What will the value of out be after the following lines of code are executed? Note that it is not 6, which is the value out is assigned inside of my_adder." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def my_adder(a, b, c):\n", - " out = a + b + c\n", - " print(f'The value out within the function is {out}')\n", - " return out\n", - "\n", - "out = 1\n", - "d = my_adder(1, 2, 3)\n", - "print(f'The value out outside the function is {out}')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The next examples are designed to be exercises in the concept of local variables. They are intentionally very confusing, but if you can untangle them, then you probably understand the local variable within a function. Focus on exactly what Python is doing, in the order that Python does it.\n", - "\n", - "##### **EXAMPLE**: \n", - " Consider the following function:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def my_test(a, b):\n", - " x = a + b\n", - " y = x * b\n", - " z = a + b\n", - " \n", - " m = 2\n", - " \n", - " print(f'Within function: x={x}, y={y}, z={z}')\n", - " return x, y" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# TRY IT! What will the value of a, b, x, y, and z be after the following code is run?\n", - "\n", - "a = 2\n", - "b = 3\n", - "z = 1\n", - "y, x = my_test(b, a)\n", - "\n", - "print(f'Outside function: x={x}, y={y}, z={z}')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "![](Figures/Code_1.png)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "EXAMPLE: Try to use and change the value n within the function." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "jupyter": { - "outputs_hidden": true - } - }, - "source": [ - "![](Figures/Code_2.png)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "EXAMPLE: Define n as the global variable, and then use and change the value n within the function." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "n = 42\n", - "\n", - "def func():\n", - " global n\n", - " print(f'Within function: n is {n}')\n", - " n = 3\n", - " print(f'Within function: change n to {n}')\n", - "\n", - "func()\n", - "print(f'Outside function: Value of n is {n}')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Nested functions\n", - "\n", - "Once you have created and saved a new function, it behaves just like any other Python built-in function. You can call the function from anywhere in the notebook, and any other function can call on the function as well. A nested function is a function that is defined within another function - parent function. Only the parent function is able to call the nested function. However, the nested function retains a separate memory block from its parent function.\n", - "\n", - "TRY IT! Consider the following function and nested function." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "\n", - "def my_dist_xyz(x, y, z):\n", - " \"\"\"\n", - " x, y, z are 2D coordinates contained in a tuple\n", - " output:\n", - " d - list, where\n", - " d[0] is the distance between x and y\n", - " d[1] is the distance between x and z\n", - " d[2] is the distance between y and z\n", - " \"\"\"\n", - " \n", - " def my_dist(x, y):\n", - " \"\"\"\n", - " subfunction for my_dist_xyz\n", - " Output is the distance between x and y, \n", - " computed using the distance formula\n", - " \"\"\"\n", - " out = np.sqrt((x[0]-y[0])**2+(x[1]-y[1])**2)\n", - " return out\n", - " \n", - " d0 = my_dist(x, y)\n", - " d1 = my_dist(x, z)\n", - " d2 = my_dist(y, z)\n", - " \n", - " return [d0, d1, d2]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Notice that the variables x and y appear in both my_dist_xyz and my_dist. This is permissible because a nested function has a separate memory block from its parent function. Nested functions are useful when a task must be performed many times within the function but not outside the function. In this way, nested functions help the parent function perform its task while hiding in the parent function." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "TRY IT! Call the function \n", - "\n", - "my_dist_xyz for x = (0, 0), y = (0, 1), z = (1, 1). \n", - "\n", - "Try to call the nested function my_dist in the following cell." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "d = my_dist_xyz((0, 0), (0, 1), (1, 1))\n", - "print(d)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "![](Figures/Code_3.png)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# If you want to call nested function, you'll see ıt's not gonna run since it is child. only parent can call the child one.\n", - "d = my_dist((0, 0), (0, 1))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Following is the code repeated without using nested function. Notice how much busier and cluttered the function looks and how much more difficult it is to understand what is going on. Also note that this version is much more prone to mistakes because you have three chances to mistype the distance formula. It is worth noting that this function could be written more compactly using vector operations. We leave this as an exercise." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "\n", - "def my_dist_xyz(x, y, z):\n", - " \"\"\"\n", - " x, y, z are 2D coordinates contained in a tuple\n", - " output:\n", - " d - list, where\n", - " d[0] is the distance between x and y\n", - " d[1] is the distance between x and z\n", - " d[2] is the distance between y and z\n", - " \"\"\"\n", - " \n", - " d0 = np.sqrt((x[0]-y[0])**2+(x[1]-y[1])**2)\n", - " d1 = np.sqrt((x[0]-z[0])**2+(x[1]-z[1])**2)\n", - " d2 = np.sqrt((y[0]-z[0])**2+(y[1]-z[1])**2)\n", - " \n", - " return [d0, d1, d2]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "d = my_dist_xyz((0, 0), (0, 1), (1, 1))\n", - "print(d)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Recursive Functions" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "![](Figures/Code_4.png)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "TRY IT! \n", - "\n", - "Write the factorial function using recursion. Use your function to compute the factorial of 3." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def factorial(n):\n", - " \"\"\"Computes and returns the factorial of n, \n", - " a positive integer.\n", - " \"\"\"\n", - " if n == 1: # Base cases!\n", - " return 1\n", - " else: # Recursive step\n", - " return n * factorial(n - 1) # Recursive call " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "![](Figures/Code_5.png)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "![](Figures/Code_6.png)\n", - "\n", - "![](Figures/Code_7.png)" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [], - "source": [ - "def fibonacci(n):\n", - " \"\"\"Computes and returns the Fibonacci of n, \n", - " a postive integer.\n", - " \"\"\"\n", - " if n == 1: # first base case\n", - " return 1\n", - " elif n == 2: # second base case\n", - " return 1\n", - " else: # Recursive step\n", - " return fibonacci(n-1) + fibonacci(n-2) # Recursive call " - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1\n", - "1\n", - "2\n", - "3\n", - "5\n" - ] - } - ], - "source": [ - "print(fibonacci(1))\n", - "print(fibonacci(2))\n", - "print(fibonacci(3))\n", - "print(fibonacci(4))\n", - "print(fibonacci(5))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "EXAMPLE: Write a function fibonacci_display that based on the Modification of fibonacci. Can you determine the order in which the Fibonacci numbers will appear on the screen for fibonacci(5)?" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def fibonacci_display(n):\n", - " \"\"\"Computes and returns the Fibonacci of n, \n", - " a postive integer.\n", - " \"\"\"\n", - " if n == 1: # first base case\n", - " out = 1\n", - " print(out)\n", - " return out\n", - " elif n == 2: # second base case\n", - " out = 1\n", - " print(out)\n", - " return out\n", - " else: # Recursive step\n", - " out = fibonacci_display(n-1)+fibonacci_display(n-2)\n", - " print(out)\n", - " return out # Recursive call " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "fibonacci_display(5)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Notice that the number of recursive calls becomes very large for even relatively small inputs for n. If you do not agree, try to draw the recursion tree for fibonacci(10). If you try your unmodified function for inputs around 35, you will notice significant computation times." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "There is an iterative method of computing the n-th Fibonacci number that requires only one workspace.\n", - "\n", - "EXAMPLE: Iterative implementation for computing Fibonacci numbers." - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "\n", - "def iter_fib(n):\n", - " fib = np.ones(n)\n", - " \n", - " for i in range(2, n):\n", - " fib[i] = fib[i - 1] + fib[i - 2]\n", - " \n", - " return fib" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "22.1 µs ± 659 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)\n" - ] - } - ], - "source": [ - "%timeit iter_fib(25)" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "35.7 ms ± 3.42 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n" - ] - } - ], - "source": [ - "%timeit fibonacci(25)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "You can see in the previous example that the iterative version runs much faster than the recursive counterpart. In general, iterative functions are faster than recursive functions that perform the same task. So why use recursive functions at all? There are some solution methods that have a naturally recursive structure. In these cases it is usually very hard to write a counterpart using loops. The primary value of writing recursive functions is that they can usually be written much more compactly than iterative functions. The cost of the improved compactness is added running time.\n", - "\n", - "The relationship between the input arguments and the running time is discussed in more detail later in the chapter on Complexity." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "EXAMPLE: Run the following function with and without an input." - ] - }