{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "This review contains some representative problems to prepare for the first midterm exam." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 1. nearby rational approximations" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Consider $S = \\sqrt{2}$\n", "\n", "1. Construct a nearby rational approximation for $S$ where the size of the denominator is not larger than 1000.\n", "\n", "2. Construct a sequence of 10 nearby rational approximations, where the denominator of the $k$-th approximation is smaller than $10^k$.\n", "\n", "3. Verify the accuracy of the rational approximations." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "S = sqrt(2)" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1393/985" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "q = RR(S).nearby_rational(max_denominator=1000)\n", "q" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "R100 = RealField(prec=100)" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[7/5,\n", " 140/99,\n", " 1393/985,\n", " 8119/5741,\n", " 114243/80782,\n", " 941664/665857,\n", " 9369319/6625109,\n", " 131836323/93222358,\n", " 1086679440/768398401,\n", " 10812186007/7645370045]" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Q = [R100(S).nearby_rational(max_denominator=10^k) for k in range(1,11)]\n", "Q" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[1, 4, 6, 8, 10, 11, 14, 16, 18, 20]" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "[floor(abs(log(abs(S - q)/abs(S), 10.0))) for q in Q]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Observe the increase in precision from ``RR`` (default 53 bits) to 100 bits in ``R100``." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 2. a function to store data" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Define a function ``whatis`` which stores definitions.\n", "\n", "Here is a session with this function:\n", "\n", "1. ``whatis('computer algebra')`` returns\n", "\n", " ``call again with the definition for computer algebra``\n", " \n", " \n", "2. ``whatis('computer algebra', 'the study of algorithms in symbolic computation')`` \n", "\n", " stores the definition for ``'computer algebra'``\n", " \n", " \n", "3. ``whatis('computer algebra')`` returns\n", "\n", " ``the study of algorithms in symbolic computation``" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "def whatis(name, *definition, D={}):\n", " if name in D:\n", " print(name,'is', D[name])\n", " else:\n", " if(len(definition) > 0):\n", " D[name] = definition[0]\n", " else:\n", " print('call again with the definition for', name)" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "call again with the definition for computer algebra\n" ] } ], "source": [ "whatis('computer algebra')" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "whatis('computer algebra', 'the study of algorithms in symbolic computation')" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "computer algebra is the study of algorithms in symbolic computation\n" ] } ], "source": [ "whatis('computer algebra')" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "call again with the definition for symbolic computation\n" ] } ], "source": [ "whatis('symbolic computation')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Using this function could be a good preparation to study the definitions we encountered in the course." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 3. Algebraic Numbers" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Consider the polynomial $p = x^4 + x^2 + 1$\n", "over the field ${\\mathbb Z}_2$, the field of bits, 0 and 1.\n", " \n", " 1. Is $p$ irreducible? If not, then what are its factors?\n", " \n", " 2. Extend the field ${\\mathbb Z}_2$ with sufficiently many formal roots\n", " so $p$ factors as a product of linear factors.\n", " \n", " Write the factorization of $p$." ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Is x^4 + x^2 + 1 irreducible? False\n" ] } ], "source": [ "reset()\n", "x = polygen(GF(2))\n", "p = x^4 + x^2 + 1\n", "print('Is', p, 'irreducible?', p.is_irreducible())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The polynomial is not irreducible, it factors." ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(x^2 + x + 1)^2" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "factor(p)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We see that the polynomial is the square of $x^2 + x + 1$." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To define the field extension, we select the irreducible factor from the list of factors." ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[(x^2 + x + 1, 2)]" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "L = list(factor(p))\n", "L" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Finite Field in r of size 2^2" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f = L[0][0]\n", "K. = GF(2).extension(f)\n", "K" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To see the factorization, we must cast the polynomial into the polynomial ring over this extended field." ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(x + r)^2 * (x + r + 1)^2" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "factor(K[x](p))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 4. Vectorization" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Write a Python function ``python_sum`` which takes on input a positive integer $n$ and which returns\n", "the floating-point value of\n", "\n", "$$\n", " \\frac{\\pi}{n} \\sum_{i=1}^{n-1} \\cos\\left( - \\frac{\\pi}{2} + i \\frac{\\pi}{n} \\right).\n", "$$\n", "\n", "Write a more efficient version ``numpy_sum`` using vectorization.\n", "\n", "Time the two versions to illustrate the efficiency." ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [], "source": [ "def python_sum(n):\n", " \"\"\"\n", " Returns the sum of cos(-pi/2 + i*(pi/n)) for i from 1 to n-1.\n", " \"\"\"\n", " return float((pi/n)*sum([cos(-pi/2 + i*(pi/n)) for i in range(1,n)]))" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1.9999983550656617" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "python_sum(1000)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To prepare the ``numpy`` version, let us experiment with ``arange`` for ``n`` equal to 10." ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [], "source": [ "from numpy import arange" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([-1/2*pi, -2/5*pi, -3/10*pi, -1/5*pi, -1/10*pi, 0, 1/10*pi, 1/5*pi,\n", " 3/10*pi, 2/5*pi], dtype=object)" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "arange(10)*(pi/10) - pi/2" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [], "source": [ "def numpy_sum(n):\n", " \"\"\"\n", " Applies numpy vectors to sum cos(-pi/2 + i*(pi/n)) for i from 1 to n-1.\n", " \"\"\"\n", " from numpy import arange, cos, pi\n", " x = arange(n-1)*(pi/n) - pi/2\n", " c = cos(x)\n", " return (pi/n)*sum(c)" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1.9999884854774963" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "numpy_sum(1000)" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "25 loops, best of 3: 21.2 ms per loop" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "timeit('python_sum(1000)')" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "625 loops, best of 3: 10.4 μs per loop" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "timeit('numpy_sum(1000)')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We see an enormous speed up, from 72 milliseconds to 31 microseconds." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 5. Fully Factored Form of Rational Polynomials" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Explain what is the fully factored normal form of rational polynomials.\n", "\n", "Why does this automatic simplification not happen automatically?\n", "\n", "Illustrate with a good example." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### answer:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The fully factored normal form of the rational polynomial is where both numerator and denominator are factored and where the common factor is removed." ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/latex": [ "$$\\newcommand{\\Bold}[1]{\\mathbf{#1}}\\frac{x^{2} - 1}{x + 1}$$" ], "text/plain": [ "(x^2 - 1)/(x + 1)" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "reset()\n", "x = var('x')\n", "q = (x^2 - 1)/(x+1)\n", "show(q)" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "normalized numerator : x - 1\n", "normalized denominator : 1\n" ] } ], "source": [ "print('normalized numerator :', q.numerator(normalize=True))\n", "print('normalized denominator :', q.denominator(normalize=True))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Because of expression swell, this normalization does not happen automatically. An example is\n", "\n", "$$\n", " \\frac{x^{1000} - 1}{x - 1}\n", "$$\n", "\n", "which leads to 1000 terms if the $x-1$ is factored out of the numerator." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 6. Expression Trees" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Type \n", "``reset(); x, y = var('x,y'); q = (x^2 - y)/(y^2 - x)``\n", "and draw the expression tree of ``q.``" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [], "source": [ "reset()\n", "x, y = var('x, y')\n", "q = (x^2 - y)/(y^2 - x)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let us ask for the operands and the operators." ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " operates on [x^2 - y, 1/(y^2 - x)]\n" ] }, { "data": { "text/plain": [ "[([x^2, -y], ),\n", " ([y^2 - x, -1], )]" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "L0 = q.operands()\n", "print(q.operator(), 'operates on', L0) \n", "L1 = [(a.operands(), a.operator()) for a in L0]\n", "L1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Observe that the division by ``(y^2 - x)`` is represented by ``(y^2 - x)^(-1)``." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We continue computing the operators and the operands." ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[([x, 2], ), ([y, -1], )]\n", "[([y^2, -x], ), ([], None)]\n" ] } ], "source": [ "L2 = L1[0][0]\n", "L3 = L1[1][0]\n", "L4 = [(a.operands(), a.operator()) for a in L2]\n", "L5 = [(a.operands(), a.operator()) for a in L3]\n", "print(L4)\n", "print(L5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There are two expressions, ``y^2`` and ``-x``, which have operands and an operator." ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[([y, 2], ),\n", " ([x, -1], )]" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "L6 = L5[0][0]\n", "[(a.operands(), a.operator()) for a in L6]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we represent ``y^2`` and ``-x`` with ``LabelledOrderedTree`` objects." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The next line is needed only if you are running WSL." ] }, { "cell_type": "code", "execution_count": 30, "metadata": { "tags": [] }, "outputs": [], "source": [ "sage.typeset.ascii_art.AsciiArt._terminal_width = lambda x: 80" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " ^_\n", " / /\n", "y 2\n", " *_\n", " / / \n", "x -1\n" ] } ], "source": [ "leafy = LabelledOrderedTree([], label='y')\n", "leaf2 = LabelledOrderedTree([], label='2')\n", "nodey2 = LabelledOrderedTree([leafy, leaf2], label='^')\n", "leafx = LabelledOrderedTree([], label='x')\n", "leafm1 = LabelledOrderedTree([], label='-1')\n", "nodexm1 = LabelledOrderedTree([leafx, leafm1], label='*')\n", "print(ascii_art(nodey2))\n", "print(ascii_art(nodexm1))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In the same fashion, we represent ``x^2`` and ``-y``." ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " ^_\n", " / /\n", "x 2\n", " *_\n", " / / \n", "y -1\n" ] } ], "source": [ "nodex2 = LabelledOrderedTree([leafx, leaf2], label='^')\n", "nodeym1 = LabelledOrderedTree([leafy, leafm1], label='*')\n", "print(ascii_art(nodex2))\n", "print(ascii_art(nodeym1))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The numerator is ``x^2 - y`` and the denominator ``y^2 - x``." ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " _+___\n", " / / \n", " ^_ *_\n", " / / / / \n", "x 2 y -1\n", " _+___\n", " / / \n", " ^_ *_\n", " / / / / \n", "y 2 x -1\n" ] } ], "source": [ "numerator = LabelledOrderedTree([nodex2, nodeym1], label='+')\n", "denominator = LabelledOrderedTree([nodey2, nodexm1], label='+')\n", "print(ascii_art(numerator))\n", "print(ascii_art(denominator))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Then at last, we take the inverse of the denominator\n", "and multiply with the numerator." ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "data": { "text/plain": [ " _______*________\n", " / / \n", " _+___ __^____\n", " / / / / \n", " ^_ *_ _+___ -1\n", " / / / / / / \n", "x 2 y -1 ^_ *_ \n", " / / / / \n", " y 2 x -1 " ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ "invden = LabelledOrderedTree([denominator, leafm1], label='^')\n", "exptree = LabelledOrderedTree([numerator, invden], label=\"*\")\n", "ascii_art(exptree)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 7. Manipulation of Expressions" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Rewrite\n", "\n", "$$\n", " x + \\frac{(x - y)^5}{(x + y)^5}\n", "$$\n", "\n", "into\n", "\n", "$$\n", " \\frac{(x + y)^5 \\cdot x + (x - y)^5}{(x + y)^5}.\n", "$$" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/latex": [ "$$\\newcommand{\\Bold}[1]{\\mathbf{#1}}x + \\frac{{\\left(x - y\\right)}^{5}}{{\\left(x + y\\right)}^{5}}$$" ], "text/plain": [ "x + (x - y)^5/(x + y)^5" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "reset()\n", "x, y = var('x, y')\n", "p = x + (x-y)^5/(x+y)^5\n", "show(p)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We need to prevent ``x+y`` and ``x-y`` from expanding. We will replace ``x+y`` and ``x-y`` by two new variables, which we must declare first." ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/latex": [ "$$\\newcommand{\\Bold}[1]{\\mathbf{#1}}x + \\frac{v^{5}}{u^{5}}$$" ], "text/plain": [ "x + v^5/u^5" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "u, v = var('u, v')\n", "q = p.subs({x+y:u, x-y:v})\n", "show(q)" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/latex": [ "$$\\newcommand{\\Bold}[1]{\\mathbf{#1}}\\frac{u^{5} x + v^{5}}{u^{5}}$$" ], "text/plain": [ "(u^5*x + v^5)/u^5" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "f = factor(q)\n", "show(f)" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/latex": [ "$$\\newcommand{\\Bold}[1]{\\mathbf{#1}}\\frac{{\\left(x + y\\right)}^{5} x + {\\left(x - y\\right)}^{5}}{{\\left(x + y\\right)}^{5}}$$" ], "text/plain": [ "((x + y)^5*x + (x - y)^5)/(x + y)^5" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "show(f(u=x+y,v=x-y))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 8. Multivariate Polynomials" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Consider $p = -y^2 z^3 - y z^4 + 3 x y^3 + x^3 + z^2$\n", "as a polynomial with integer coefficients in the variables $x$, $y$, and $z$.\n", " \n", "The monomials of $p$ are sorted in the degree lexicographical order.\n", " \n", "Convert $p$ (*without retyping $p$!*) into the pure lexicographical term order." ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/latex": [ "$$\\newcommand{\\Bold}[1]{\\mathbf{#1}}-y^{2} z^{3} - y z^{4} + 3 x y^{3} + x^{3} + z^{2}$$" ], "text/plain": [ "-y^2*z^3 - y*z^4 + 3*x*y^3 + x^3 + z^2" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "reset()\n", "R. = PolynomialRing(ZZ)\n", "p = -y^2*z^3 - y*z^4 + 3*x*y^3 + x^3 + z^2\n", "show(p)" ] }, { "cell_type": "code", "execution_count": 40, "metadata": { "tags": [] }, "outputs": [ { "data": { "text/html": [ "" ], "text/latex": [ "$$\\newcommand{\\Bold}[1]{\\mathbf{#1}}x^{3} + 3 x y^{3} - y^{2} z^{3} - y z^{4} + z^{2}$$" ], "text/plain": [ "x^3 + 3*x*y^3 - y^2*z^3 - y*z^4 + z^2" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "Rlex. = PolynomialRing(ZZ, order='lex')\n", "q = Rlex(p)\n", "show(q)" ] } ], "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.6" } }, "nbformat": 4, "nbformat_minor": 4 }