Lecture 12: Rational Functions and Conversions ============================================== One of the main problems in computer algebra is :index:`expression swell`. In an exact calculation, *expression swell* happens when the numbers and or expressions grow exponentially in size. A rational number is simplified immediately, but in rational expressions removing the greatest common denominator may not always result in a smaller expression and may even lead to expression swell. If we consider \ :math:`\frac{x^d - 1}{x - 1}`, for any degree \ :math:`d` then the reason becomes clear. Rational Expressions -------------------- SageMath recognizes rational expressions as of type ``fraction_field_elements`` of ``sage.rings``. :: x = polygen(QQ) p = x^3 - 1; q = x^2 - 1; r = p/q print(r, 'has type', type(r)) What is remarkable is that the rational expression is normalized automatically. The normalization of a rational expression is the removal of the greatest common divisor of numerator and denominator. We see that the common factor ``x - 1`` is removed in r. :: print(factor(p)); print(factor(q)) This automatic normalization may lead to expression swell. :: f = (x^1000 - 1)/(x-1); print(f) We see an expression with 1,000 terms! Instead of printing the entire expression, we may just as well only ask for just the number of terms. The problem is that ``f`` is still not a polynomial and we have to take its fraction before getting the number of coefficients. :: print(type(f)) fn = f.numerator() print(type(fn)) print(len(fn.coefficients())) We can :index:`freeze an expression`, by conversion to a Symbolic Ring (SR). :: g = SR(p)/q; print(g); This shows the original expression ``(x^3 - 1)/(x^2 - 1)``. We can ask for the denominator, with or without normalization :: print(g.denominator(normalize=False)) print(g.denominator(normalize=True)) The same for the numerator, with or without normalization :: print(g.numerator(normalize=False)) print(g.numerator(normalize=True)) We may represent a rational expression with numerator and denominator in factored form, or not. :: fn = g.numerator(normalize=False).factor() fd = g.denominator(normalize=False).factor() print(SR(fn)/g.denominator(normalize=False)) print(g.numerator(normalize=False)/SR(fd)) This prints ``(x^2 + x + 1)*(x - 1)/(x^2 - 1)`` and ``(x^3 - 1)/((x + 1)*(x - 1))``. Factoring or expanding the numerator, factoring or expanding the denominator defines four :index:`normal forms of rational expressions`. If we really do not want to remove common factors, then we must explicitly convert to strings. :: print(str(fn) + '/' + '(' + str(fd) + ')') which shows ``(x^2 + x + 1)*(x - 1)/((x + 1)*(x - 1))``. Conversions ----------- The coercion to a symbolic ring SR on a polynomial shows the so-called :index:`Horner form` of the polynomial. :: x = SR.var('x') p = x^4 + 2*x^3 + 3*x^2 + 4*x + 5 print(p.horner(x)) The Horner form gives an efficient way to evaluate a polynomial, which requires as many multiplications as additions, for the example polynomial ``p``, the Horner form is ``(((x+2)*x + 3)*x + 4)*x + 5``. The disadvantage of working with x = polygen(QQ) is that we cannot select a random element from the ring. :: P. = PolynomialRing(CC) rn = P.random_element(degree = 4) rd = P.random_element(degree = 4) f = rn/rd print(f, 'has type', type(f)) To evaluate a rational expression efficiently, we may consider a partial fraction decomposition. :: print(f.partial_fraction_decomposition()) Assignments ----------- 1. Assign to ``r`` the expression ``(4*x^2 + x)/(x^2 + 4)``. Use the methods ``operands()`` and ``operator()`` to draw the expression tree of ``r``. 2. Consider the rational expression ``p = (x^4 + x^3 - 4*x^2-4*x)/(x^4 + x^3 - x^2 - x)``. What are the commands to transform ``p`` into ``(x + 2)*(x + 1)*(x - 2)/(x^3 + x^2 - x - 1)``? 3. What is the partial fraction decomposition of ``p = (x^4 + x^3 - 4*x^2-4*x)/(x^4 + x^3 - x^2 - x)``? 4. Consider the polynomial :math:`p` in :math:`x` with rational coefficients: .. math:: p = \frac{1}{12} x^8 + \frac{93}{4} x^7 - x^6 + 2 x^5 + \frac{5}{39} x^4 + \frac{1}{5} x^3 + x^2 - \frac{1}{5} x + \frac{1}{2}. Without retyping \ :math:`p`, convert :math:`p` into the polynomial .. math:: q = \frac{1}{2} x^8 - \frac{1}{5} x^7 + x^6 + \frac{1}{5} x^5 + \frac{5}{39} x^4 + 2 x^3 - x^2 + \frac{93}{4} x + \frac{1}{12}. which has the same coefficients as :math:`p`, but swapped. If :math:`c_k` is the coefficient with :math:`x^k` in :math:`p`, then in :math:`q`, the monomial :math:`x^{8-k}` has coefficient :math:`c_k`, for :math:`k = 0, 1, \ldots, 8`.