|
2902 | 2902 | "id": "cognitive-toolbox" |
2903 | 2903 | }, |
2904 | 2904 | "source": [ |
2905 | | - "## Activity: Compound function\n", |
| 2905 | + "## Activity 30: Function Composition\n", |
2906 | 2906 | "\n", |
2907 | | - "- For a given function (f), starting point (a0) and number of iteration (m), write a function that calculates f(a0), f(f(a0)), ..., f(f(f(...f(a0)))))" |
| 2907 | + "At this point, we presume you understand how functions work: \n", |
| 2908 | + "- they take in values, \n", |
| 2909 | + "- and output values. \n", |
| 2910 | + "\n", |
| 2911 | + "When the output of one function becomes the input for another, we have a special name for it: *function composition*.\n", |
| 2912 | + "\n", |
| 2913 | + "In this activity, you are given a function `f`, an initial value `a0`, and some number of iterations to perform, `m`. How would you write Python code to show how the value of `a` changes as it is passed to `f`, over `m` iterations?\n", |
| 2914 | + "\n", |
| 2915 | + "Return the values $a$<sub>1</sub>, $a$<sub>2</sub>, $a$<sub>3</sub>, and $a$<sub>4</sub>, using a `list`. Please round your answers to 8 decimal places." |
2908 | 2916 | ], |
2909 | 2917 | "id": "cognitive-toolbox" |
2910 | 2918 | }, |
| 2919 | + { |
| 2920 | + "cell_type": "markdown", |
| 2921 | + "metadata": { |
| 2922 | + "id": "xClzxxP1Fkyv" |
| 2923 | + }, |
| 2924 | + "source": [ |
| 2925 | + "### Example Input\n", |
| 2926 | + "In mathematics, whenever we have a function that takes in the output of another as a parameter, then we call that a *compound function*.\n", |
| 2927 | + "\n", |
| 2928 | + "In this activity, `f` is a compound function (note that you could also call it a *recursive function*, since it takes the output of itself as a parameter). \n", |
| 2929 | + "\n", |
| 2930 | + "Consider the function $f(x) = \\frac{x + n}{2x}$. Let's see how an initial value of `1.0` changes over `4` iterations:\n", |
| 2931 | + "```\n", |
| 2932 | + "Input:\n", |
| 2933 | + "f = lambda x: (x+n/x)/2 # our function\n", |
| 2934 | + "n = 2 \n", |
| 2935 | + "a0 = 1.0 # the initial value\n", |
| 2936 | + "m = 4 # the number of iterations\n", |
| 2937 | + "\n", |
| 2938 | + "Output\n", |
| 2939 | + "[1.5, 1.41666667, 1.41421569, 1.41421356]\n", |
| 2940 | + "\n", |
| 2941 | + "Explanation:\n", |
| 2942 | + "This output is the result of the following:\n", |
| 2943 | + "[\n", |
| 2944 | + " round(output, 8) for output in (\n", |
| 2945 | + " f(a0), \n", |
| 2946 | + " f(f(a0)), \n", |
| 2947 | + " f(f(f(a0))), \n", |
| 2948 | + " f(f(f(f(a0))))\n", |
| 2949 | + " )\n", |
| 2950 | + "]\n", |
| 2951 | + "``` " |
| 2952 | + ], |
| 2953 | + "id": "xClzxxP1Fkyv" |
| 2954 | + }, |
2911 | 2955 | { |
2912 | 2956 | "cell_type": "code", |
2913 | 2957 | "metadata": { |
2914 | | - "id": "rubber-terry", |
2915 | | - "outputId": "5b8b3558-ff3f-4d57-e9bf-b4f2cce63acc" |
| 2958 | + "id": "I3DzpHX2Kj6w" |
2916 | 2959 | }, |
2917 | 2960 | "source": [ |
2918 | | - "f= lambda x: (x+n/x)/2\n", |
2919 | | - "n = 2\n", |
2920 | | - "a0 = 1.0\n", |
2921 | | - "m = 4\n", |
2922 | | - "# This implementation is not good as it is hard-coded\n", |
2923 | | - "print([round(x, 8) for x in (f(a0), f(f(a0)), f(f(f(a0))), f(f(f(f(a0)))))])" |
| 2961 | + "f = lambda x: (x+n/x)/2 # our function\n", |
| 2962 | + "n = 2 \n", |
| 2963 | + "a0 = 1.0 # the initial value\n", |
| 2964 | + "m = 4 # the number of iterations" |
2924 | 2965 | ], |
2925 | | - "id": "rubber-terry", |
2926 | | - "execution_count": null, |
2927 | | - "outputs": [ |
2928 | | - { |
2929 | | - "output_type": "stream", |
2930 | | - "text": [ |
2931 | | - "[1.5, 1.41666667, 1.41421569, 1.41421356]\n" |
2932 | | - ], |
2933 | | - "name": "stdout" |
2934 | | - } |
2935 | | - ] |
| 2966 | + "id": "I3DzpHX2Kj6w", |
| 2967 | + "execution_count": 27, |
| 2968 | + "outputs": [] |
| 2969 | + }, |
| 2970 | + { |
| 2971 | + "cell_type": "markdown", |
| 2972 | + "metadata": { |
| 2973 | + "id": "WJVrZ1HUJqG1" |
| 2974 | + }, |
| 2975 | + "source": [ |
| 2976 | + "### Solution 1: Using a Generator\n", |
| 2977 | + "While you could simply implement the code in the \"Explanation\" section above, it wouldn't be very readable, and it would stop working the moment the value of `m` changes.\n", |
| 2978 | + "\n", |
| 2979 | + "Therefore, it is much more preferable to create a function to complete this activity. In a separate activity we can do something like this using a `generator` function in Python, via the `yield` keyword:" |
| 2980 | + ], |
| 2981 | + "id": "WJVrZ1HUJqG1" |
2936 | 2982 | }, |
2937 | 2983 | { |
2938 | 2984 | "cell_type": "code", |
2939 | 2985 | "metadata": { |
2940 | | - "id": "informational-cuisine", |
2941 | | - "outputId": "6f95ea62-721a-487a-dcae-f52014b273ec" |
| 2986 | + "id": "informational-cuisine" |
2942 | 2987 | }, |
2943 | 2988 | "source": [ |
2944 | | - "def repeat(f, a, m):\n", |
| 2989 | + "def compound_function(f, a, m):\n", |
| 2990 | + " # compute the value of a after each iteration\n", |
2945 | 2991 | " for _ in range(m):\n", |
| 2992 | + " # apply the function\n", |
2946 | 2993 | " a = f(a) \n", |
2947 | | - " yield a\n", |
2948 | | - " \n", |
2949 | | - "for i in repeat(f, 1, 4):\n", |
2950 | | - " print(round(i, 8))" |
| 2994 | + " # output the result (don't forget to round!)\n", |
| 2995 | + " yield round(a, 8)" |
2951 | 2996 | ], |
2952 | 2997 | "id": "informational-cuisine", |
2953 | | - "execution_count": null, |
| 2998 | + "execution_count": 28, |
| 2999 | + "outputs": [] |
| 3000 | + }, |
| 3001 | + { |
| 3002 | + "cell_type": "markdown", |
| 3003 | + "metadata": { |
| 3004 | + "id": "MBBobFw7LfQN" |
| 3005 | + }, |
| 3006 | + "source": [ |
| 3007 | + "#### Test Out Solution 1\n", |
| 3008 | + "Recall we can use a `for` loop to iterate over the values returned by a `generator` object:" |
| 3009 | + ], |
| 3010 | + "id": "MBBobFw7LfQN" |
| 3011 | + }, |
| 3012 | + { |
| 3013 | + "cell_type": "code", |
| 3014 | + "metadata": { |
| 3015 | + "colab": { |
| 3016 | + "base_uri": "https://localhost:8080/" |
| 3017 | + }, |
| 3018 | + "id": "uOI3asirLtG8", |
| 3019 | + "outputId": "b311d371-d4b9-4797-ab95-ab2048e34b58" |
| 3020 | + }, |
| 3021 | + "source": [ |
| 3022 | + "for output in compound_function(f, a0, m):\n", |
| 3023 | + " print(output)" |
| 3024 | + ], |
| 3025 | + "id": "uOI3asirLtG8", |
| 3026 | + "execution_count": 29, |
2954 | 3027 | "outputs": [ |
2955 | 3028 | { |
2956 | 3029 | "output_type": "stream", |
|
2970 | 3043 | "id": "close-trinity" |
2971 | 3044 | }, |
2972 | 3045 | "source": [ |
2973 | | - "### Note: the above compound iteration will converge to $\\sqrt{n}$ " |
| 3046 | + "### Special Note: Convergence\n", |
| 3047 | + "Did you notice anything special about $f(x)$ in Activity 30? *Hint:* try increasing the number of iterations `m`, and trying out different values of `n` - then see if you spot a familiar pattern!\n", |
| 3048 | + "\n", |
| 3049 | + "<hr>\n", |
| 3050 | + "\n", |
| 3051 | + "#### The Answer:\n", |
| 3052 | + "\n", |
| 3053 | + "As the number of iterations `m` increases, the outputs of the compound function $f(x)$ converges to $\\sqrt{n}$. \n", |
| 3054 | + "\n", |
| 3055 | + "We can even verify this by comparing it with the result of the `numpy.sqrt` function!\n" |
2974 | 3056 | ], |
2975 | 3057 | "id": "close-trinity" |
2976 | 3058 | }, |
2977 | 3059 | { |
2978 | 3060 | "cell_type": "code", |
2979 | 3061 | "metadata": { |
2980 | 3062 | "id": "freelance-skiing", |
2981 | | - "outputId": "20727ae8-d2b0-46da-ee6a-323aa61279c8" |
| 3063 | + "colab": { |
| 3064 | + "base_uri": "https://localhost:8080/" |
| 3065 | + }, |
| 3066 | + "outputId": "7a137816-a27f-496b-c772-a67ac7b782cd" |
2982 | 3067 | }, |
2983 | 3068 | "source": [ |
2984 | | - "# Note: the above coumpound iteration will converge to np.sqrt(n) \n", |
2985 | 3069 | "import numpy as np\n", |
2986 | 3070 | "np.sqrt(n)" |
2987 | 3071 | ], |
2988 | 3072 | "id": "freelance-skiing", |
2989 | | - "execution_count": null, |
| 3073 | + "execution_count": 32, |
2990 | 3074 | "outputs": [ |
2991 | 3075 | { |
2992 | 3076 | "output_type": "execute_result", |
|
2998 | 3082 | "metadata": { |
2999 | 3083 | "tags": [] |
3000 | 3084 | }, |
3001 | | - "execution_count": 203 |
| 3085 | + "execution_count": 32 |
3002 | 3086 | } |
3003 | 3087 | ] |
3004 | 3088 | } |
|
0 commit comments