# Rational functions


{{< include ../_common_code.qmd >}}

This section uses the following add-on packages:


```{julia}
using CalculusWithJulia
using SymPy
using Plots
plotly()
import Polynomials
using RealPolynomialRoots
```

The `Polynomials` package is "imported" to avoid naming collisions with `SymPy`;some names may need to be qualified.



---


A rational expression is the ratio of two polynomial expressions. Such expressions arise in many modeling situations. As many facts are known about polynomial expressions, much can be determined about rational expressions.  This section covers some additional details that arise when graphing such expressions.


## Rational functions


The rational numbers are simply ratios of integers, of the form $p/q$ for non-zero $q$. A rational function is a ratio of *polynomial* *functions* of the form $p(x)/q(x)$, again $q$ is non-zero, but may have zeros.


We know that polynomials have nice behaviors due to the following facts:


* Behaviors at $-\infty$, $\infty$ are known just from the leading term.

* There are possible wiggles up and down, the exact behavior depends on intermediate terms, but there can be no more than $n-1$ wiggles.

* The number of real zeros is no more than $n$, the degree of the polynomial.


Rational functions are not quite so nice:


* behavior at $-\infty$ and  $\infty$ can be like a polynomial of any degree, including constants

* behaviour at any value x can blow up due to division by $0$---rational functions, unlike polynomials, need not be always defined

* The function may or may not cross zero, even if the range includes every other point, as the graph of $f(x) =1/x$ illustrates.


Here, as with our discussion on polynomials, we are interested for now in just a few properties:


  * What happens to $f(x)$ when $x$ gets really big or really small (towards $\infty$ or $-\infty$)?
  * What happens near the values where $q(x) = 0$?
  * When is $f(x) = 0$?


These questions can often be answered with a graph, but with rational functions we will see that care must be taken to produce a useful graph.


For example, consider this graph generated from a simple rational function:


$$
f(x) = \frac{(x-1)^2 \cdot (x-2)}{(x+3) \cdot (x-3)}.
$$

::: {#fig-plot-rational-f-over-minus10-10-bad-choice}
```{julia}
f(x) = (x-1)^2 * (x-2) / ((x+3)*(x-3) )
plot(f, -10, 10)
```

Basic plot of the rational function $f(x)$ over $[-10,10]$. As no extra effort was made to adjust the $y$-viewing window, the graphic is not to useful for identifying basic properties of the function.
:::

We would be hard pressed to answer any of the three questions above from the @fig-plot-rational-f-over-minus10-10-bad-choice, though, on inspection, we might think the strange spikes have something to do with $x$ values where $q(x)=0$.


The question of big or small $x$ is not answered well with this graph, as the spikes dominate the scale of the $y$-axis. Setting a much larger viewing window illuminates this question:

::: {#fig-plot-rational-f-over-minus100-100-can-see-slant-asymptote}
```{julia}
plot(f, -100, 100)
```

Plot of rational function $f(x)$ over $[-100, 100]$ allowing the slant asymptote to be identified
:::
We can see from this, that the function eventually looks like a slanted straight line. The *eventual* shape of the graph is something that can be determined just from the two leading terms.


The spikes haven't vanished completely. It is just that with only a few hundred points to make the graph, there aren't any values near enough to the problem to make a large spike. The spikes happen because the function has a *vertical asymptote* at these values. Though not quite right, it is reasonable to think of the graph being made by selecting a few hundred points in the specified domain, computing the corresponding $y$ values, plotting the pairs, and finally connecting the points with straight line segments.  Near a vertical asymptote the function values can be arbitrarily large in absolute values, though at the vertical asymptote the function is undefined. This graph doesn't show such detail.


The spikes will be related to the points where $q(x) = 0$, though not necessarily all of them.


Where the function crosses $0$ is very hard to tell from these two graphs. As well, other finer features, such as local peaks or valleys, when present, can be hard to identify as the $y$-scale is set to accommodate the  asymptotes. Working around the asymptotes requires some extra effort. Strategies are discussed herein.


## Asymptotes


Formally, an [asymptote](http://en.wikipedia.org/wiki/Asymptote) of a curve is a line such that the distance between the curve and the line approaches $0$ as they tend to infinity. Tending to infinity can happen as $x \rightarrow \pm \infty$ *or* $y \rightarrow \pm \infty$, the former being related to *horizontal asymptotes* or *slant asymptotes*, the latter being related to *vertical asymptotes*.


### Behaviour as $x \rightarrow \infty$ or $x \rightarrow -\infty$.


Let's look more closely at our example rational function using symbolic math.


In particular, let's rewrite the expression in terms of its numerator and denominator:


```{julia}
@syms x::real
num = (x-1)^2 * (x-2)
den = (x+3) * (x-3)
```

Euclid's [division](https://en.wikipedia.org/wiki/Polynomial_greatest_common_divisor#Euclidean_division) algorithm can be used for polynomials $a(x)$ and $b(x)$ to produce $q(x)$ and $r(x)$ with $a = b\cdot q + r$ *and* the degree of $r(x)$ is less than the degree of $b(x)$. This is in direct analogy to the division algorithm of integers, only there the value of the remainder, $r(x)$, satisfies $0 \leq r < b$. Given $q(x)$ and $r(x)$ as above, we can reexpress the rational function


$$
\frac{a(x)}{b(x)} = q(x)  + \frac{r(x)}{b(x)}.
$$

The rational expression on the right-hand side has larger degree in the denominator.


The division algorithm is implemented in `Julia` generically through the `divrem` method:


```{julia}
q, r = divrem(num, den)
```

This yields the decomposition of `num/den`:


```{julia}
q + r/den
```

A similar result can be found using the `apart` function, which can be easier to use if the expression is not given in terms of a separate numerator and denominator.


```{julia}
g(x) = (x-1)^2 * (x-2) / ((x+3)*(x-3))  # as a function
h = g(x)                                # a symbolic expression
apart(h)
```

This decomposition breaks the rational expression into two pieces: $x-4$ and $40/(3x+9) + 2/(3x-9)$. The first piece would have a graph that is the line with slope $1$ and $y$-intercept $4$. As $x$ goes to $\infty$, the second piece will clearly go towards $0,$ as @fig-plot-aparth-minus-x-minus-4-over-10-100 shows.

::: {#fig-plot-aparth-minus-x-minus-4-over-10-100}
```{julia}
plot(apart(h) - (x - 4), 10, 100)
```
Plot of just remainder term of the rational function $g(x)$ after reduction showing the decay towards $0$ as $x$ gets large
:::

Similarly, a plot over $[-100, -10]$ would show decay towards $0$, though in that case from below. Combining these two facts then, it is now no surprise that the graph of the rational function $f(x)$ should approach a straight line, in this case $y=x-4$, as $x \rightarrow \pm \infty$.


We can easily do most of this analysis without needing a computer or algebra. First, we should know the four eventual shapes of a polynomial, that the graph of $y=mx$ is a line with slope $m$, the graph of $y = c$ is a constant line at height $c$, and the graph of $y=c/x^m$, $m > 0$ will decay towards $0$ as $x \rightarrow \pm\infty$. The latter should be clear, as $x^m$ gets big, so its reciprocal goes towards $0$.


The factored form, as $h$ is presented, is a bit hard to work with, rather we use the expanded form, which we get through the `cancel` function


```{julia}
cancel(h)
```

We can see that the numerator is of degree $3$ and the denominator of degree $2$.  The leading terms are $x^3$ and $x^2$, respectively. If we were to pull those out we would get:


$$
\frac{x^3 \cdot (1 - 4/x + 5/x^2 - 2/x^3)}{x^2 \cdot (1 - 9/x^2)}.
$$

The terms $(1 - 4/x + 5/x^2 - 2/x^3)$ and $(1 - 9/x^2)$ go towards $1$ as $x \rightarrow \pm \infty$, as each term with $x$ goes towards $0$. So the dominant terms comes from the ratio of the leading terms, $x^3$ and $x^2$. This ratio is $x$, so their will be an asymptote around a line with slope $1$. (The fact that the asymptote is $y=x-4$ takes a bit more work, as a division step is needed.)


Just by looking at the ratio of the two leading terms, the behaviour as $x \rightarrow \pm \infty$ can be discerned. If this ratio is of the form:


* $c x^m$ with $m > 1$ then the shape will follow the polynomial growth of the monomial $c x^m$;

* $c x^m$ with  $m=1$ then there will be a line with slope $c$ as a *slant asymptote*;

* $cx^0$ with  $m=0$ (or just $c$) then there will be a *horizontal asymptote* $y=c$;

* $c/x^{m}$ with $m  >  0$ then there will be a horizontal asymptote $y=0$, or the $y$ axis.


To expand on the first point, where the degree of the numerator is greater than that of the denominator, we have from the division algorithm that if $a(x)$ is the numerator and $b(x)$ the denominator, then $a(x)/b(x) = q(x) + r(x)/b(x)$ where the degree of $b(x)$ is greater than the degree of $r(x)$, so the right-most term will have a horizontal asymptote of $0$. This says that the graph will eventually approach the graph of $q(x)$, giving more detail than just saying it follows the shape of the leading term of $q(x)$, at the expense of the work required to find $q(x)$.


### Examples


Consider the rational expression


$$
\frac{17x^5 - 300x^4 - 1/2}{x^5 - 2x^4 + 3x^3 - 4x^2 + 5}.
$$

The leading term of the numerator is $17x^5$ and the leading term of the denominator is $x^5$. The ratio is $17$ (or $17x^0 = 17x^{5-5}$). As such, we would have a horizontal asymptote $y=17$.


---


If we consider instead this rational expression:


$$
\frac{x^5 - 2x^4 + 3x^3 - 4x^2 + 5}{5x^4 + 4x^3 + 3x^2 + 2x + 1}
$$

Then we can see that the ratio of the leading terms is $x^5 / (5x^4) = (1/5)x$. We expect a slant asymptote with slope $1/5$, though we would need to divide to see the exact intercept. This is found with, say:


```{julia}
#| hold: true
p = (x^5 - 2x^4 + 3x^3 - 4x^2 + 5) / (5x^4 + 4x^3 + 3x^2 + 2x + 1)
div(numerator(p), denominator(p))  # or apart(p)
```

---


The rational function


$$
\frac{5x^3 + 6x^2 + 2}{x-1}
$$

has decomposition $5x^2 + 11x + 11 + 13/(x-1)$:


```{julia}
top = 5x^3 + 6x^2 +2
bottom = x-1
quo, rem = divrem(top, bottom)
```


@fig-asymptote-matches-for-large-x shows that for small $x$ ($\lvert x\rvert \approx 0$) the graph of the rational function and `quo` are not similar, but that they are  when $x$ is larger.

::: {#fig-asymptote-matches-for-large-x}

```{julia}
#| echo: false
p1 = plot(top/bottom, -3, 3; title="small x", label="p/q")
plot!(quo, -3, 3; line=(3, :red), label="quo")

p2 = plot(top/bottom, 5, 10; title="larger x", label="p/q")
plot!(quo, 5, 10; label="quo")

plot(p1, p2)
```
The asymptotic nature is similar to the function for larger $x$ values.
:::


Finally, consider this rational expression in factored form:


$$
\frac{(x-2)^3\cdot(x-4)\cdot(x-3)}{(x-5)^4 \cdot (x-6)^2}.
$$

By looking at the powers we can see that the leading term of the numerator will the $x^5$ and the leading term of the denominator $x^6$. The ratio is $1/x^1$. As such, we expect the $x$-axis as a horizontal asymptote.


#### Partial fractions


The `apart` function is used to express a rational function in terms of a polynomial plus additional rational functions whose horizontal asymptotes are $0$.  This function computes the partial fraction [decomposition](https://en.wikipedia.org/wiki/Partial_fraction_decomposition) of a rational function. Outside of the initial polynomial, this decomposition is a reexpression of a rational function into a sum of rational functions, where the denominators are *irreducible*, or unable to be factored further over the set of rational numbers and the numerators have lower degree than the denominator. Hence the horizontal asymptotes of $0$.


To see another example we have:


```{julia}
#| hold: true
p = (x-1)*(x-2)
q = (x-3)^3 * (x^2 - x - 1)
apart(p/q)
```

The denominator, $q$, has factors $x-3$ and $x^2 - x - 1$, each irreducible. The answer is expressed in terms of a sum of rational functions each with a denominator coming from one of these factors, possibly with a power.


### Vertical asymptotes


As just discussed, the graph of $1/x$ will have a horizontal asymptote. However its graph (@fig-plot-1-over-x-over-minus1-1-showing-vertical-asymptote)  also shows a spike at $0$.

::: {#fig-plot-1-over-x-over-minus1-1-showing-vertical-asymptote}
```{julia}
plot(1/x, -1, 1)
```

Plot of $f(x) = 1/x$ over $[-1,1]$. The vertical asymptote at $0$ dominates the display, preventing other features to be identified.
:::

Again, this spike is an artifact of the plotting algorithm. The $y$ values for $x$-values just smaller than $0$ are large negative values and the $x$ values just larger than $0$ produce large, positive $y$ values.


The two points with $x$ components closest to $0$ are connected with a line, though that is misleading.  @fig-plot-of-1-over-x-few-points we deliberately use far fewer points to plot $1/x$ to show how this happens:

::: {#fig-plot-of-1-over-x-few-points}

```{julia}
#| hold: true
f(x) = 1/x
xs = range(-1, 1, length=12)
ys = f.(xs)
plot(xs, ys; legend=false)
scatter!(xs, ys)
```

Plot of $f(x) = 1/x$ with few points to illustrate how "spikes" can be artifacts of the plotting algorithm
:::

The line $x = 0$ is a *vertical asymptote* for the graph of $1/x$. As $x$ values get close to $0$ from the right, the $y$ values go towards $\infty$ and as the $x$ values get close to $0$ on the left, the $y$ values go towards $-\infty$.


This has everything to do with the fact that $0$ is a root of the denominator.


For a rational function $p(x)/q(x)$, the roots of $q(x)$ may or may not lead to vertical asymptotes. For a root $c$ if $p(c)$ is not zero then the line $x=c$ will be a vertical asymptote. If $c$ is a root of both $p(x)$ and $q(x)$, then we can rewrite the expression as:


$$
\frac{p(x)}{q(x)} = \frac{(x-c)^m r(x)}{(x-c)^n s(x)},
$$

where both $r(c)$ and $s(c)$ are non zero. Knowing $m$ and $n$ (the multiplicities of the root $c$) allows the following to be said:

* If $m < n$ then $x=c$ will be a vertical asymptote.

* If $m \geq n$ then $x=c$ will not be vertical asymptote. (The value $c$ will be known as a removable singularity). In this case, the graph of $p(x)/q(x)$ and the graph of $(x-c)^{m-n}r(x)/s(x)$ will differ, though very slightly, as the latter will include a value for $x=c$, whereas $x=c$ is not in the domain of $p(x)/q(x)$.


Finding the multiplicity may or may not be hard, but there is a very kludgy quick check that is often correct. With `Julia`, if you have a rational function that has `f(c)` evaluate to `Inf` or `-Inf` then there will be a vertical asymptote. If the expression evaluates to `NaN`, more analysis is needed. (The value of `0/0` is `NaN`, whereas `1/0` is `Inf`.)


For example, the function $f(x) = ((x-1)^2 \cdot (x-2)) / ((x+3) \cdot(x-3))$ has vertical asymptotes at $-3$ and $3$, as its graph illustrated. Without the graph we could see this as well:


```{julia}
#| hold: true
f(x) = (x-1)^2 * (x-2) / ((x+3)*(x-3) )
f(3), f(-3)
```

#### Graphing with vertical asymptotes


As seen in several graphs, the basic plotting algorithm does a poor job with vertical asymptotes. For example, it may erroneously connect their values with a steep vertical line, or the $y$-axis scale can get so large as to make reading the rest of the graph impossible. There are some tricks to work around this.


Consider again the function $f(x) = ((x-1)^2 \cdot (x-2)) / ((x+3) \cdot(x-3))$. Without much work, we can see that $x=3$ and $x=-3$ will be vertical asymptotes and there will be a slant asymptote with slope $1$. How to graph this?

::: {#fig-rational-function-avoiding-spikes}
```{julia}
#| echo: false
f(x) = (x-1)^2 * (x-2) / ((x+3)*(x-3) )
p1 = plot(f, -5, 5; legend=false,
          title="no effort", xlabel="(a)")
p2 = plot(f, -2.9, 2.9; legend=false,
          title = "restrict domain", xlabel="(b)")
p3 = plot(f, -20, 20; ylims=(-20, 20),
          legend=false,
          title ="set ylims", xlabel="(c)")
p4 = plot(rangeclamp(f, 30), -20, 20; legend=false,
          title="rangeclamp", xlabel="(d)")

plot(p1, p2, p3, p4; layout = 4)

```

Four ways to plot the rational function $f(x)$: (a) has no effort, (b) restricts the plot domain, (c) uses `ylims` to restrict the viewing window, (d) calls `rangeclamp` to break lines when there are larger values.
:::


@fig-rational-function-avoiding-spikes shows four graphics, produced along the lines of:

```{julia}
#| eval: false
f(x) = (x-1)^2 * (x-2) / ((x+3)*(x-3))
plot(f, -5, 5)
```

This no effort approach shows the reason extra effort should be taken. This extra effort can come in terms of limiting the $x$ viewing window by backing off from the boundaries $(-3, 3)$:


```{julia}
#| eval: false
plot(f, -2.9, 2.9)
```

Extra effort can come by limiting the $y$ viewing window through `ylims`:

```{julia}
#| eval: false
plot(f, -20, 20, ylims=(-20, 20))
```

This isn't ideal, as the large values are still computed, just the viewing window is clipped. This leaves the vertical asymptotes still effecting the graph.


Finally, we show the use of `rangeclamp` from the `CalculusWithJulia` package which replaces the plotted values with `NaN` when they are large (in absolute value). This breaks the lines.


```{julia}
#| eval: false
plot(rangeclamp(f, 30), -20, 20)
```

### Sign charts


When sketching graphs of rational functions by hand, it is useful to use sign charts. A sign chart of a function indicates when the function is positive, negative, $0$, or undefined. It typically is represented along the lines of this one for $f(x) = x^3 - x$:


```{verbatim}
    -    0   +   0   -   0   +
< ----- -1 ----- 0 ----- 1 ----- >
```

The usual recipe for construction follows these steps:


  * Identify when the function is $0$ or undefined. Place those values on a number line.
  * Identify "test points" within each implied interval (these are $(-\infty, -1)$, $(-1,0)$, $(0,1)$, and $(1, \infty)$ in the example) and check for the sign of $f(x)$ at these test points. Write in `-`, `+`, `0`, or `*`, as appropriate. The value comes from the fact that "continuous" functions may only change sign when they cross $0$ or are undefined.


With the computer, where it is convenient to draw a graph, it might be better to emphasize the sign on the graph of the function, but at times numeric values are preferred. The `sign_chart` function from `CalculusWithJulia` does this analysis by numerically identifying points where the function is $0$ or $\infty$ and indicating any sign change as $x$ crosses over these points.


```{julia}
#| hold: true
f(x) = x^3 - x
sign_chart(f, -3/2, 3/2)
```

This format is a bit different from above, but shows from $-3/2$ to the left of $-1$ a minus sign; between $-1$ and $0$ a plus sign; between $0$ and $1$ a minus sign; and between $1$ and $3/2$ a plus sign.

## Pade approximate


One area where rational functions are employed is in approximating functions. Later, the Taylor polynomial will be seen to be a polynomial that approximates well a function (where "well" will be described later). The Pade approximation is similar, though uses a rational function for the form $p(x)/q(x)$, where $q(0)=1$ is customary.


Some example approximations are


$$
\sin(x) \approx \frac{x - 7/60 \cdot x^3}{1 + 1/20 \cdot x^2}
$$

and


$$
\tan(x) \approx \frac{x - 1/15 \cdot x^3}{1 - 2/5 \cdot x^2}
$$

@fig-pade-approximations show these approximations through a graph.

::: {#fig-pade-approximations}

```{julia}
#| echo: false
sin_p(x) = (x - (7/60)*x^3) / (1 + (1/20)*x^2)
tan_p(x) = (x - (1/15)*x^3) / (1 - (2/5)*x^2)
p1 = plot(sin, -pi, pi; label="sin")
plot!(p1, sin_p, -pi, pi; label="pade approx")

Δ = 0.1
p2 = plot(tan, -pi/2 +  Δ, pi/2 - Δ; label="tan")
plot!(p2, tan_p, -pi/2 + Δ, pi/2 - Δ; label="pade approx")

plot(p1, p2)
```

Small-degree Pade approximations for $\sin(x)$ and $\tan(x)$.
:::

## The `Polynomials` package for rational functions


In the following, we import some functions from the `Polynomials` package. We avoided loading the entire namespace, as there are conflicts with `SymPy`. Here we import some useful functions and the `Polynomial` constructor:


```{julia}
import Polynomials: Polynomial, variable, lowest_terms, fromroots, coeffs
```

The `Polynomials` package has support for rational functions. The `//` operator can be used to create rational expressions from polynomial expressions:


```{julia}
x = variable()
p = (x-1)*(x-2)^2
q = (x-2)*(x-3)
pq = p // q
```

A rational expression is a formal object; a rational function the viewpoint that this object will be evaluated by substituting  values for the indeterminate. Rational expressions made within `Polynomials` are evaluated just like functions:


```{julia}
pq(4)  # p(4)/q(4)
```

The rational expressions are not in lowest terms unless requested through the `lowest_terms` method:


```{julia}
lowest_terms(pq)
```

For polynomials as simple as these, this computation is not a problem, but there is the very real possibility that the lowest term computation may be incorrect. Unlike `SymPy` which factors symbolically, `lowest_terms` uses a numeric algorithm and does not, as would be done by hand or with `SymPy`, factor the polynomial and then cancel common factors.


The distinction between the two expressions is sometimes made; the initial expression is not defined at $x=2$; the reduced one is, so the two are not identical when viewed as functions of the variable $x$.


Rational expressions include polynomial expressions, just as the rational numbers include the integers. The identification there is to divide by $1$, thinking of $3$ as $3/1$. In `Julia`, we would just use


```{julia}
3//1
```

The integer can be recovered from the rational number using `numerator`:


```{julia}
numerator(3//1)
```

Similarly, we can divide a polynomial by the polynomial $1$, which in `Julia` is returned by `one(p)`, to produce a rational expression:


```{julia}
pp = p // one(p)
```

And as with rational numbers, `p` is recovered by `numerator`:


```{julia}
numerator(pp)
```

One difference is the rational number `3//1` also represents other expressions, say `6/2` or `12/4`, as `Julia`'s rational numbers are presented in lowest terms, unlike the rational expressions in `Polynomials`.


Rational functions also have a plot recipe defined for them that attempts to ensure the basic features are identifiable. As previously discussed, a plot of a rational function can require some effort to avoid the values associated to vertical asymptotes taking up too many of the available vertical pixels in a graph.


For the polynomial `pq` above, we have from observation that $1$ and $2$ will be zeros and $x=3$ a vertical asymptote. We also can identify a slant asymptote with slope $1$. These are hinted at in @fig-basic-plot-recipe-rational-function


::: {#fig-basic-plot-recipe-rational-function}
```{julia}
plot(pq)
```

Plot of rational function `pq` using the basic plot recipe. The vertical asymptote is clear, but the slant asymptote requires a trained eye.
:::

To better see the zeros, a plot over a narrower interval, say $[0,2.5]$, would be encouraged; to better see the slant asymptote, a plot over a wider interval, say $[-10,10]$, would be encouraged.


For one more example of the default plot recipe, we redo the graphing of the rational expression we earlier plotted with `rangeclamp` in @fig-plot-rational-function-with-asymptotes-at-minus3-3-from-pq-recipe.

::: {#fig-plot-rational-function-with-asymptotes-at-minus3-3-from-pq-recipe}
```{julia}
#| hold: true
p,q = fromroots([1,1,2]), fromroots([-3,3])
plot(p//q; legend=false)
```
A plot of a rational function with vertical  asymptotes at $x= \pm 3$. The plot recipe avoids showing artifacts from the vertical asymptotes.
:::

##### Example: Transformations of polynomials; real roots


We have seen some basic transformations of functions such as shifts and scales. For a polynomial expression we can implement these as follows, taking advantage of polynomial evaluation:


```{julia}
#| hold: true
x = variable()
p = 3 + 4x + 5x^2
a = 2
p(a*x), p(x+a) # scale, shift
```

A different polynomial transformation is inversion, or the mapping $x^d \cdot p(1/x)$ where $d$ is the degree of $p$. This will yield a polynomial, as perhaps this example will convince you:


```{julia}
#| hold: true
p = Polynomial([1, 2, 3, 4, 5])
d = Polynomials.degree(p)  # degree is in SymPy and Polynomials, indicate which
pp = p // one(p)
x = variable(pp)
q = x^d * pp(1/x)
lowest_terms(q)
```

We had to use a rational expression so that division by the variable was possible. The above indicates that the new polynomial, $q$, is constructed from $p$ by **reversing** the coefficients.


Inversion is like a funhouse mirror, flipping around parts of the polynomial. For example, the interval $[1/4,1/2]$ is related to the interval $[2,4]$. Of interest here, is that if $p(x)$ had a root, $r$, in $[1/4,1/2]$ then $q(x) = x^d \cdot p(1/x)$ would have a root in $[2,4]$ at $1/r$.


So these three transformations – scale, shift, and inversion – can be defined for polynomials.


Combined, the three can be used to create a [Mobius transformation](https://en.wikipedia.org/wiki/M%C3%B6bius_transformation). For two values $a$ and $b$, consider the polynomial derived from $p$ (again `d=degree(p)`) by:


$$
q = (x+1)^d \cdot p(\frac{ax + b}{x + 1}).
$$

Here is a non-performant implementation as a `Julia` function:


```{julia}
function mobius_transformation(p, a, b)
  x = variable(p)
  p = p(x + a)   # shift
  p = p((b-a)*x) # scale
  p = Polynomial(reverse(coeffs(p))) # invert
  p = p(x + 1)   # shift
  p
end
```

We can verify this does what we want through example with the previously defined `p`:


```{julia}
p = Polynomial([1, 2, 3, 4, 5])
q = mobius_transformation(p, 4, 6)
```

As contrasted with


```{julia}
#| hold: true
a, b = 4, 6

pq = p // one(p)
x = variable(pq)
d = Polynomials.degree(p)
numerator(lowest_terms( (x + 1)^d * pq((a*x + b)/(x + 1))))
```

---


Now, why is this of any interest?


Mobius transforms are used to map regions into other regions. In this special case, the transform $\phi(x) = (ax + b)/(x + 1)$ takes the interval $[0,\infty]$ and sends it to $[a,b]$  ($0$ goes to $(a\cdot 0 + b)/(0+1) = b$, whereas $\infty$ goes to $ax/x \rightarrow a$). Using this, if $p(u) = 0$, with $q(x) = (x+1)^d p(\phi(x))$,  then setting $u = \phi(x)$ we have

$$
\begin{align*}
q(x) &= (x+1)^d p(\phi(x))\\
&= (\phi^{-1}(u)+1)^d p(\phi(\phi^{-1}(u))) \\
& =  (\phi^{-1}(u)+1)^d \cdot  p(u) \\
& =  (\phi^{-1}(u)+1)^d \cdot 0 = 0.\\
\end{align*}
$$

That is, a zero of $p$ in $[a,b]$ will appear as a zero of $q$ in $[0,\infty)$ at $x = \phi^{-1}(u)$.


The Descartes rule of signs applied to $q$ then will give a bound on the number of possible roots of $p$ in the interval $[a,b]$. In the example we did, the Mobius transform for $a=4, b=6$ is $15 - x - 11x^2 - 3x^3$ with $1$ sign change, so there must be exactly $1$ real root of $p=(x-1)(x-3)(x-5)$ in the interval $[4,6]$, as we can observe from the factored form of $p$.


Similarly, we can see there are $2$ or $0$ roots for $p$ in the interval $[2,6]$ by counting the two sign changes here:


```{julia}
p = fromroots([1,3,5])               #  (x-1)⋅(x-3)⋅(x-5) = -15 + 23*x - 9*x^2 + x^3
mobius_transformation(p, 2,6)
```

This observation, along with a detailed analysis provided by [Kobel, Rouillier, and Sagraloff](https://dl.acm.org/doi/10.1145/2930889.2930937) provides a means to find intervals that enclose the real roots of a polynomial.


The basic algorithm, as presented next, is fairly simple to understand, and hints at the bisection algorithm to come. It is due to Akritas and Collins. Suppose you know the only possible positive real roots are between $0$ and $M$ *and* no roots are repeated. Find the transformed polynomial over $[0,M]$:


* If there are no sign changes, then there are no roots of $p$ in $[0,M]$.

* If there is one sign change, then there is a single root of $p$ in $[0,M]$. The interval $[0,M]$ is said to isolate the root (and the actual root can then be found by other means)

* If there is more than one sign change, divide the interval in two ($[0,M/2]$ and $[M/2,M]$, say) and apply the same consideration to each.


Eventually, *mathematically* this will find isolating intervals for each positive real root. (The negative ones can be similarly isolated.)


Applying these steps to $p$ with an initial interval, say $[0,9]$, we would have:


```{julia}
#| hold: true
mobius_transformation(p, 0, 9) # 3
mobius_transformation(p, 0, 9//2)    # 2
mobius_transformation(p, 9//2, 9)    # 1 (and done)
mobius_transformation(p, 0, 9//4)    # 1 (and done)
mobius_transformation(p, 9//4, 9//2) # 1 (and done)
```

So the three roots ($1$, $3$, $5$) are isolated by $[0, 9/4]$, $[9/4, 9/2]$, and $[9/2, 9]$.


### The `RealPolynomialRoots` package.


For square-free polynomials, the `RealPolynomialRoots` package implements a basic version of the  paper of [Kobel, Rouillier, and Sagraloff](https://dl.acm.org/doi/10.1145/2930889.2930937) to identify the real roots of a polynomial using the Descartes rule of signs and the Möbius transformations just described.


The `ANewDsc` function takes a collection of coefficients representing a polynomial and returns isolating intervals for each real root. For example:


```{julia}
p₀ = fromroots([1, 3, 5])
st = ANewDsc(coeffs(p₀))
```

These intervals can be refined to give accurate approximations to the roots:


```{julia}
refine_roots(st)
```

More challenging problems can be readily handled by this package. The following polynomial


```{julia}
s = variable(:s)
u = -1 + 254*s - 16129*s^2 + s^15
```

has three real roots, two of which are clustered very close to each other:


```{julia}
st = ANewDsc(coeffs(u))
```

and


```{julia}
refine_roots(st)
```

The `Hecke.jl` package has a `roots` function that handles the task of root isolation more performantly than `ANewDsc`.
The SymPy package (`sympy.real_roots`) can accurately identify the three roots but it can take a **very** long time. The `Polynomials.roots` function from the `Polynomials` package identifies the cluster as complex valued. Though the implementation in `RealPolynomialRoots` doesn't handle such large polynomials, the authors of the algorithm have implementations that can quickly solve polynomials with degrees as high as $10,000$.


## Questions


###### Question


The rational expression $(x^3 - 2x + 3) / (x^2 - x + 1)$ would have


```{julia}
#| hold: true
#| echo: false
choices = [L"A horizontal asymptote $y=0$",
L"A horizontal asymptote $y=1$",
L"A slant asymptote with slope $m=1$"]
answer = 3
explanation = L"The ratio of the two leading terms is $x$"
buttonq(choices, answer; explanation)
```

###### Question


The rational expression $(x^2 - x + 1)/ (x^3 - 2x + 3)$ would have


```{julia}
#| hold: true
#| echo: false
choices = [L"A horizontal asymptote $y=0$",
L"A horizontal asymptote $y=1$",
L"A slant asymptote with slope $m=1$"]
answer = 1
explanation = L"The ratio of the two leading terms is $1/x$"
buttonq(choices, answer; explanation)
```

###### Question


The rational expression $(x^2 - x + 1)/ (x^2 - 3x + 3)$ would have


```{julia}
#| hold: true
#| echo: false
choices = [L"A horizontal asymptote $y=0$",
L"A horizontal asymptote $y=1$",
L"A slant asymptote with slope $m=1$"]
answer = 2
explanation = L"The ratio of the two leading terms can be seen to be $1$"
buttonq(choices, answer; explanation)
```

###### Question


The rational expression


$$
\frac{(x-1)\cdot(x-2)\cdot(x-3)}{(x-4)\cdot(x-5)\cdot(x-6)}
$$

would have


```{julia}
#| hold: true
#| echo: false
choices = [L"A horizontal asymptote $y=0$",
L"A horizontal asymptote $y=1$",
L"A slant asymptote with slope $m=1$"]
answer = 2
explanation = L"the ratio of the leading terms is $1$"
buttonq(choices, answer; explanation)
```

###### Question


The rational expression


$$
\frac{(x-1)\cdot(x-2)\cdot(x-3)}{(x-4)\cdot(x-5)\cdot(x-6)}
$$

would have


```{julia}
#| hold: true
#| echo: false
choices = [L"A vertical asymptote $x=1$",
L"A slant asymptote with slope $m=1$",
L"A vertical asymptote $x=5$"
]
answer = 3
explanation = L"the ratio of the leading terms is $1$, not $x$ and there are vertical asymptotes at $x=4,5,6$"
buttonq(choices, answer; explanation)
```

###### Question


The rational expression


$$
\frac{x^3 - 3x^2 + 2x}{3x^2 - 6x + 2}
$$

has a slant asymptote. What is the equation of that line?


```{julia}
#| hold: true
#| echo: false
choices = [
    "``y = 3x``",
    "``y = (1/3)x``",
    "``y = (1/3)x - (1/3)``"
]
answer = 3
explanation = "Try `div(x^3 - 3x^2+ 2x, 3x^2 - 6x +2)`"
buttonq(choices, answer)
```

###### Question


Look at the graph of the function $f(x) = ((x-1)\cdot(x-2)) / ((x-3)\cdot(x-4))$


```{julia}
#| hold: true
#| echo: false
f(x) = ((x-1) * (x-2)) / ((x-3) *(x-4))
delta = 1e-1
col = :blue
p = plot(f, -1, 3-delta, color=col, legend=false)
plot!(p, f, 3+delta, 4-3delta, color=col)
plot!(p,f, 4 + 5delta, 9, color=col)
p
```

Is the following common conception true: "The graph of a function never crosses its asymptotes."


```{julia}
#| hold: true
#| echo: false
choices = ["No, the graph clearly crosses the drawn asymptote",
"Yes, this is true"]
answer = 1
buttonq(choices, answer)
```

(The wikipedia page indicates that the term "asymptote" was introduced by Apollonius of Perga in his work on conic sections, but in contrast to its modern meaning, he used it to mean any line that does not intersect the given curve. It can sometimes take a while to change perception.)


###### Question


Consider the two graphs of $f(x) = 1/x$ over $[10,20]$ and $[100, 200]$:

::: {#fig-plot-1-over-x-10-to-20-100-to-200}
```{julia}
#| hold: true
#| echo: false
p1 = plot(x -> 1/x, 10, 20)
p2 = plot(x -> 1/x, 100, 200)
plot(p1, p2)
```

The graph of $f(x) = 1/x$ over different viewing windows
:::

The two shapes are basically identical and do not look like straight lines. How does this reconcile with the fact that $f(x)=1/x$ has a horizontal asymptote $y=0$?


```{julia}
#| hold: true
#| echo: false
choices = ["The horizontal asymptote is not a straight line.",
L"The $y$-axis scale shows that indeed the $y$ values are getting close to $0$.",
L"The graph is always decreasing, hence it will eventually reach $-\infty$."
]
answer = 2
buttonq(choices, answer)
```

###### Question


The amount of drug in a bloodstream after $t$ hours is modeled by the rational function


$$
r(t) = \frac{50t^2}{t^3 + 20}, \quad t \geq  0.
$$

What is the amount of the drug after $1$ hour?


```{julia}
#| echo: false
r1(t) = 50t^2 / (t^3 + 20)
```

```{julia}
#| hold: true
#| echo: false
val = r1(1)
numericq(val)
```

What is the amount of drug in the bloodstream after 24 hours?


```{julia}
#| hold: true
#| echo: false
val = r1(24)
numericq(val)
```

What is more accurate: the peak amount is


```{julia}
#| hold: true
#| echo: false
choices = ["between ``0`` and ``8`` hours",
           "between ``8`` and ``16`` hours",
           "between ``16`` and ``24`` hours",
           "after one day"]
answer = 1
buttonq(choices, answer)
```

This graph has


```{julia}
#| hold: true
#| echo: false
choices = [L"a slant asymptote with slope $50$",
L"a horizontal asymptote $y=20$",
L"a horizontal asymptote $y=0$",
L"a vertical asymptote with $x = 20^{1/3}$"]
answer = 3
buttonq(choices, answer)
```

###### Question


The (low-order) Pade approximation for $\sin(x)$ was seen to be $(x - 7/60 \cdot x^3)/(1 + 1/20 \cdot x^2)$. The graph showed that this approximation was fairly close over $[-\pi, \pi]$. Without graphing would you expect the behaviour of the function and its approximation to be similar for *large* values of $x$?


```{julia}
#| hold: true
#| echo: false
yesnoq(false)
```

Why?


```{julia}
#| hold: true
#| echo: false
choices = [
L"The $\sin(x)$ oscillates, but the rational function eventually follows $7/60 \cdot x^3$",
L"The $\sin(x)$ oscillates, but the rational function has a slant asymptote",
L"The $\sin(x)$ oscillates, but the rational function has a non-zero horizontal asymptote",
L"The $\sin(x)$ oscillates, but the rational function has a horizontal asymptote of $0$"]
answer = 2
buttonq(choices, answer)
```
