{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "Lecture 15 of mcs 320 is on normalization." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 1. Normalization of Expressions" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "When are two expressions the same? Consider the following example." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(x + y)*x\n", "x^2 + x*y\n" ] } ], "source": [ "x, y = var('x, y')\n", "e1 = x*(x + y)\n", "e2 = x^2 + x*y\n", "print(e1)\n", "print(e2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Although ``e1`` and ``e2`` look different, we know that they are mathematically equivalent." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "e1.operands() : [x + y, x]\n", "e2.operands() : [x^2, x*y]\n", "e1.operator() : \n", "e2.operator() : \n" ] } ], "source": [ "print('e1.operands() :', e1.operands())\n", "print('e2.operands() :', e2.operands())\n", "print('e1.operator() :', e1.operator())\n", "print('e2.operator() :', e2.operator())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Viewed as expressions, ``e1`` and ``e2`` are entirely different, and yet mathematically equivalent. Let us look at their difference." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(x + y)*x - x^2 - x*y" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d = e1 - e2\n", "d" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d.expand()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In fully expanded form, the difference collapses to zero and therefore we computed that ``e1`` and ``e2`` are the same." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 2. Rewriting Multivariate Polynomials" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can cast the expressions ``e1`` and ``e2`` into the polynomial ring in the variables ``x`` and ``y`` and with integer coefficients. The monomial order imposed by the cast will normalize the expressions." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "x^2 + x*y has type \n" ] } ], "source": [ "p1 = ZZ[x,y](e1)\n", "print(p1, 'has type', type(p1))" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "x^2 + x*y has type \n" ] } ], "source": [ "p2 = ZZ[x,y](e2)\n", "print(p2, 'has type', type(p2))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The ``p1`` and ``p2`` obtained by respectively casting ``e1`` and ``e2`` into ``ZZ[x,y]`` are identical." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p1 - p2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There are many monomial orders. We distinguish between the pure lexicographic and the degree lexicographic as the two main ones. The first choice we make is the order of the variables, which by default is alphabetically." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let us look at a random polynomial with integer coefficients, in ``x``, ``y`` and ``z``, with the monomials ordered lexicographically." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/latex": [ "$$\\newcommand{\\Bold}[1]{\\mathbf{#1}}-x^{5} z - 3 x^{4} y z^{2} + x^{4} z + x^{3} z^{4} - x^{2} y z^{3} - 3 x y z^{5} + 2 x y z^{3} - y^{5} z - y^{5} - y^{4} z^{4} - y^{3} z^{4} + 2 y^{3} z + y^{2} - 2 y z^{7} - 3 y z^{4}$$" ], "text/plain": [ "-x^5*z - 3*x^4*y*z^2 + x^4*z + x^3*z^4 - x^2*y*z^3 - 3*x*y*z^5 + 2*x*y*z^3 - y^5*z - y^5 - y^4*z^4 - y^3*z^4 + 2*y^3*z + y^2 - 2*y*z^7 - 3*y*z^4" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "Plex. = PolynomialRing(ZZ, order='lex')\n", "p = Plex.random_element(degree=8, terms=20)\n", "show(p)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let us now reorder the monomials, using as variable order z > y > x (reverse lexicographic) and order by degrees (which is the default)." ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "scrolled": true }, "outputs": [ { "data": { "text/html": [ "" ], "text/latex": [ "$$\\newcommand{\\Bold}[1]{\\mathbf{#1}}-2 z^{7} y - z^{4} y^{4} - z^{4} y^{3} - 3 z^{5} y x + z^{4} x^{3} - 3 z^{2} y x^{4} - z y^{5} - z^{3} y x^{2} - z x^{5} - 3 z^{4} y - y^{5} + 2 z^{3} y x + z x^{4} + 2 z y^{3} + y^{2}$$" ], "text/plain": [ "-2*z^7*y - z^4*y^4 - z^4*y^3 - 3*z^5*y*x + z^4*x^3 - 3*z^2*y*x^4 - z*y^5 - z^3*y*x^2 - z*x^5 - 3*z^4*y - y^5 + 2*z^3*y*x + z*x^4 + 2*z*y^3 + y^2" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "Pdeg. = PolynomialRing(ZZ)\n", "q = Pdeg(p)\n", "show(q)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Observe the different positions of the monomials." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 3. A Numerical Test on Equality" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Because the number of monomials may grow exponentially with increasing number of variables, rewriting a polynomial is often two expensive. Consider again our two expressions from the beginning." ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Is (x + y)*x the same as x^2 + x*y ?\n" ] } ], "source": [ "print('Is', e1, 'the same as', e2, '?')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Expressions are callable, let use pick a random point and compare the values of ``e1`` and ``e2`` at that random point." ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(0.884182251438780 + 0.625612760600956*I,\n", " -0.451739336032167 + 0.842882600846518*I)" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = CC.random_element()\n", "b = CC.random_element()\n", "(a, b)" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "-0.536351086441882 + 1.56895934102189*I" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v1 = e1(x=a,y=b)\n", "v1" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "-0.536351086441882 + 1.56895934102189*I" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v2 = e2(x=a,y=b)\n", "v2" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1.11022302462516e-16 - 2.22044604925031e-16*I" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v1 - v2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Up to machine precision, the values are the same. To gain more confidence, take more samples and increase the precision." ] } ], "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" } }, "nbformat": 4, "nbformat_minor": 4 }