{ "cells": [ { "cell_type": "markdown", "id": "00d79b32-352b-440e-9f8d-0bfdbd50c80c", "metadata": {}, "source": [ "MCS 320 Quiz 3 Wednesday 26 June 2024" ] }, { "cell_type": "markdown", "id": "d1d3e267-a7bc-4019-a751-461844fa0539", "metadata": {}, "source": [ "# Question 1" ] }, { "cell_type": "markdown", "id": "408f597d-a177-491c-87a6-3375f09190a3", "metadata": {}, "source": [ "Draw the binary expression tree defined by the fast callable object \n", "for $(x^2 y - 3 z^2 + 2)/(x z + 3 y)$." ] }, { "cell_type": "markdown", "id": "6ce7a912-d81d-4327-a197-3146b629b280", "metadata": {}, "source": [ "## answer to question 1" ] }, { "cell_type": "code", "execution_count": 1, "id": "0342cb23-5b20-415e-9dc2-3b488b689152", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "div(add(sub(mul(ipow(v_0, 2), v_1), mul(3, ipow(v_2, 2))), 2), add(mul(v_0, v_2), mul(3, v_1)))\n" ] } ], "source": [ "from sage.ext.fast_callable import ExpressionTreeBuilder\n", "etb = ExpressionTreeBuilder(vars=['x','y', 'z'])\n", "x = etb.var('x')\n", "y = etb.var('y')\n", "z = etb.var('z')\n", "p = (x^2*y - 3*z^2 + 2)/(x*z + 3*y)\n", "print(p)" ] }, { "cell_type": "code", "execution_count": 2, "id": "015d86fe-a9b6-4dd1-b781-80c96650a593", "metadata": {}, "outputs": [], "source": [ "Lx = LabelledBinaryTree([None, None], label='v_0')\n", "Ly = LabelledBinaryTree([None, None], label='v_1')\n", "Lz = LabelledBinaryTree([None, None], label='v_2')\n", "L2 = LabelledBinaryTree([None, None], label='2')\n", "L3 = LabelledBinaryTree([None, None], label='3')" ] }, { "cell_type": "code", "execution_count": 3, "id": "09834a49-8ba6-40e5-a33e-81285fa92061", "metadata": {}, "outputs": [ { "data": { "text/plain": [ " _ipow_\n", " / \\\n", "v_0 2" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Nxp2 = LabelledBinaryTree([Lx, L2], label=\"ipow\")\n", "ascii_art(Nxp2)" ] }, { "cell_type": "code", "execution_count": 4, "id": "beeef8e3-ae6d-4965-8346-3a60ed7d3536", "metadata": {}, "outputs": [ { "data": { "text/plain": [ " ___mul___\n", " / \\\n", " _ipow_ v_1\n", " / \\ \n", "v_0 2 " ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Nxp2y = LabelledBinaryTree([Nxp2, Ly], label=\"mul\")\n", "ascii_art(Nxp2y)" ] }, { "cell_type": "code", "execution_count": 5, "id": "acff1b10-8148-4098-baff-56ed185b7836", "metadata": {}, "outputs": [ { "data": { "text/plain": [ " _ipow_\n", " / \\\n", "v_2 2" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Nzp2 = LabelledBinaryTree([Lz, L2], label=\"ipow\")\n", "ascii_art(Nzp2)" ] }, { "cell_type": "code", "execution_count": 6, "id": "08dc155d-60cd-476f-a4cf-f63c70c56e2f", "metadata": {}, "outputs": [ { "data": { "text/plain": [ " _mul__\n", " / \\\n", "3 _ipow_\n", " / \\\n", " v_2 2" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "N3zp2 = LabelledBinaryTree([L3, Nzp2], label=\"mul\")\n", "ascii_art(N3zp2)" ] }, { "cell_type": "code", "execution_count": 7, "id": "b57d8397-e237-46d1-82c6-99a7609553fd", "metadata": {}, "outputs": [ { "data": { "text/plain": [ " ______sub______\n", " / \\\n", " ___mul___ _mul__\n", " / \\ / \\\n", " _ipow_ v_1 3 _ipow_\n", " / \\ / \\\n", "v_0 2 v_2 2" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Nxp2ysub3zp2 = LabelledBinaryTree([Nxp2y, N3zp2], label=\"sub\")\n", "ascii_art(Nxp2ysub3zp2)" ] }, { "cell_type": "code", "execution_count": 8, "id": "6aa0f3c6-54c0-4ad7-9fe3-678dd033f309", "metadata": {}, "outputs": [ { "data": { "text/plain": [ " ___________add___________\n", " / \\\n", " ______sub______ 2\n", " / \\ \n", " ___mul___ _mul__ \n", " / \\ / \\ \n", " _ipow_ v_1 3 _ipow_ \n", " / \\ / \\ \n", "v_0 2 v_2 2 " ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "numerator = LabelledBinaryTree([Nxp2ysub3zp2, L2], label=\"add\")\n", "ascii_art(numerator)" ] }, { "cell_type": "code", "execution_count": 9, "id": "de071793-56dd-4e70-8f0a-42ba22028bb7", "metadata": {}, "outputs": [ { "data": { "text/plain": [ " _mul_\n", " / \\\n", "v_0 v_2" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Nxmulz = LabelledBinaryTree([Lx, Lz], label=\"mul\")\n", "ascii_art(Nxmulz)" ] }, { "cell_type": "code", "execution_count": 10, "id": "6d8fd7cf-2cb9-4365-9bdd-f4737f70afd7", "metadata": {}, "outputs": [ { "data": { "text/plain": [ " mul\n", " / \\\n", "3 v_1" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "N3y = LabelledBinaryTree([L3, Ly], label=\"mul\")\n", "ascii_art(N3y)" ] }, { "cell_type": "code", "execution_count": 11, "id": "995fda34-b034-4b05-91a4-83fe0e7198e1", "metadata": {}, "outputs": [ { "data": { "text/plain": [ " ____add_____\n", " / \\\n", " _mul_ mul\n", " / \\ / \\\n", "v_0 v_2 3 v_1" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "denominator = LabelledBinaryTree([Nxmulz, N3y], label=\"add\")\n", "ascii_art(denominator)" ] }, { "cell_type": "code", "execution_count": 12, "id": "7bf5c000-fffa-4d57-9657-3e1fb054a082", "metadata": {}, "outputs": [ { "data": { "text/plain": [ " ____________div____________\n", " / \\\n", " ___________add___________ ____add_____\n", " / \\ / \\\n", " ______sub______ 2 _mul_ mul\n", " / \\ / \\ / \\\n", " ___mul___ _mul__ v_0 v_2 3 v_1\n", " / \\ / \\ \n", " _ipow_ v_1 3 _ipow_ \n", " / \\ / \\ \n", "v_0 2 v_2 2 " ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ptree = LabelledBinaryTree([numerator, denominator], label=\"div\")\n", "ascii_art(ptree)" ] }, { "cell_type": "markdown", "id": "b684a006-c36c-4d7f-a1a4-6e30049a1305", "metadata": {}, "source": [ "# Question 2" ] }, { "cell_type": "markdown", "id": "502e86c3-d223-4d8f-803e-56d3da73f836", "metadata": {}, "source": [ "The function\n", "\n", "`f = lambda n: float(sum([(k/n)^3 for k in range(1, n+1)])/n)`\n", "\n", "computes the right hand side of\n", "$$\n", " \\qquad \\int_0^1 t^3 dt \\approx \\frac{1}{n} \n", " \\sum_{k=1}^{n} \\left(\\frac{k}{n} \\right)^3.\n", "$$\n", "\n", "1. Time the execution of `f` for $n = 10000$. Explain why `f` is inefficient.\n", "\n", "2. Apply vectorization to improve the efficiency. Verify the correctness.\n", "\n", " Time the execution of the vectorized function for $n = 10000$\n", " and compare with the timings of `f`." ] }, { "cell_type": "markdown", "id": "dd9ec563-f13d-4b4f-a8b7-674e60d01fda", "metadata": {}, "source": [ "## answer to item 1 of question 2" ] }, { "cell_type": "code", "execution_count": 13, "id": "dc07272e-ebc1-4ef0-9fdb-44dd11687ec1", "metadata": {}, "outputs": [], "source": [ "f = lambda n: float(sum([(k/n)^3 for k in range(1, n+1)])/n)" ] }, { "cell_type": "code", "execution_count": 14, "id": "8089b284-ff8f-4b6b-9837-e9c98dbe0d87", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "125 loops, best of 3: 6.04 ms per loop" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "timeit('f(10000)')" ] }, { "cell_type": "markdown", "id": "6f0453c8-34c0-42da-afb8-23c4daba9758", "metadata": {}, "source": [ "The function `f` is inefficient because all arguments of the sum are computed in exact rational arithmetic." ] }, { "cell_type": "markdown", "id": "95c15091-64d4-4816-ad6b-dc9f069d4681", "metadata": {}, "source": [ "## answer to item 2 of question 2" ] }, { "cell_type": "code", "execution_count": 15, "id": "4317b58c-c29e-41b7-b613-ab7d78e28400", "metadata": {}, "outputs": [], "source": [ "def vf(n):\n", " \"\"\"\n", " Vectorized version of f.\n", " \"\"\"\n", " from numpy import arange\n", " a = arange(1, n+1)/float(n)\n", " return sum(a^3)/n" ] }, { "cell_type": "markdown", "id": "b4655dd1-fb26-4c0a-a885-6afcab1873df", "metadata": {}, "source": [ "First we verify the correctness, to see if f(100) agrees with vf(100)." ] }, { "cell_type": "code", "execution_count": 16, "id": "2ef17874-4546-4b47-8a1b-e7f5893505f5", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.255025" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f(100)" ] }, { "cell_type": "code", "execution_count": 17, "id": "f42881d2-9253-40e4-a4ee-ef91fe7b0904", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.25502500000000006" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "vf(100)" ] }, { "cell_type": "code", "execution_count": 18, "id": "fd2d3ca7-31e4-4038-8a80-0190c5a5e2aa", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5.551115123125783e-17" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "abs(f(100) - vf(100))" ] }, { "cell_type": "markdown", "id": "01d2ec22-cca0-4e11-8575-399d56b8a3de", "metadata": {}, "source": [ "The error is less than the machine precision. Now we do the timing and the comparison with the times." ] }, { "cell_type": "code", "execution_count": 19, "id": "9c2c5a28-c5d9-48f9-af95-be93d2eb4937", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "625 loops, best of 3: 94.3 μs per loop" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "timeit('vf(10000)')" ] }, { "cell_type": "markdown", "id": "f0b320dc-01b7-4bbd-a372-6a42a6827a75", "metadata": {}, "source": [ "The time unit dropped from about 6 milliseconds (ms) to about 90 microseconds (us)." ] } ], "metadata": { "kernelspec": { "display_name": "SageMath 10.3", "language": "sage", "name": "sagemath" }, "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.10.14" } }, "nbformat": 4, "nbformat_minor": 5 }