# An application of the resultant

I will soon release an update of **qspray** on CRAN as well as a new package: **resultant**. This post shows an application of these two packages.

Consider the two algebraic curves \(f(x,y)=0\) and \(g(x,y)=0\) where \[ f(x, y) = y^4 - y^3 + y^2 - 2x^2y + x^4 \quad \text{ and } \quad g(x, y) = y - 2x^2. \] We will derive their intersection points. First of all, let’s plot them.

```
function(x, y) {
f <-^4 - y^3 + y^2 - 2*x^2*y + x^4
y
}
function(x, y) {
g <-- 2*x^2
y
}
# contour line for f(x,y)=0
seq(-1.2, 1.2, len = 2000)
x <- seq(0, 1, len = 2000)
y <- outer(x, y, f)
z <- contourLines(x, y, z, levels = 0)
crf <-# contour line for g(x,y)=0
seq(-1, 1, len = 2000)
x <- seq(0, 1.5, len = 2000)
y <- outer(x, y, g)
z <- contourLines(x, y, z, levels = 0) crg <-
```

Theoretically there is only one contour line for both. But for some technical reasons, `crf`

is split into several pieces:

```
length(crf)
## [1] 16
```

So we need a helper function to construct the dataframe that we will pass to `ggplot2::geom_path`

:

```
function(xs) {
intercalateNA <-if(length(xs) == 1L) {
xs[[1L]]else {
} c(xs[[1L]], NA, intercalateNA(xs[-1L]))
}
} function(cr) {
contourData <- lapply(cr, `[[`, "x")
xs <- lapply(cr, `[[`, "y")
ys <-data.frame("x" = intercalateNA(xs), "y" = intercalateNA(ys))
}
contourData(crf)
datf <- contourData(crg) datg <-
```

I also plot the intersection points that we will derive later:

```
data.frame("x" = c(-0.5, 0, 0.5), "y" = c(0.5, 0, 0.5))
datPoints <-
library(ggplot2)
ggplot() +
geom_path(aes(x, y), data = datf, linewidth = 1, color = "blue") +
geom_path(aes(x, y), data = datg, linewidth = 1, color = "green") +
geom_point(aes(x, y), data = datPoints, size = 2)
```

Now we compute the *resultant* of the two polynomials with respect to \(x\):

```
# define the two polynomials
library(qspray)
qlone(1)
x <- qlone(2)
y <- f(x, y)
P <- g(x, y)
Q <-# compute their resultant with respect to x
resultant::resultant(P, Q, var = 1) # var=1 <=> var="x"
Rx <-prettyQspray(Rx, vars = "x")
## [1] "16*x^8 - 32*x^7 + 24*x^6 - 8*x^5 + x^4"
```

We need the roots of the resultant \(R_x\). I use **giacR** to get them:

```
library(giacR)
Giac$new()
giac <- sprintf("roots(%s)", prettyQspray(Rx, vars = "x"))
command <-$execute(command)
giac## [1] "[[0,4],[1/2,4]]"
$close()
giac## NULL
```

Thus there are two roots: \(0\) and \(1/2\) (the output of **GIAC** also provides their multiplicities). Luckily, they are rational, so we can use `substituteQspray`

to replace \(y\) with each of these roots in \(P\) and \(Q\). We firstly do the substitution \(y=0\):

```
substituteQspray(P, c(NA, "0"))
Px <- substituteQspray(Q, c(NA, "0"))
Qx <-prettyQspray(Px, "x")
## [1] "x^4"
prettyQspray(Qx, "x")
## [1] "(-2)*x^2"
```

Clearly, \(0\) is the unique common root of these two polynomials. One can conclude that \((0,0)\) is an intersection point.

Now we do the substitution \(y=1/2\):

```
substituteQspray(P, c(NA, "1/2"))
Px <- substituteQspray(Q, c(NA, "1/2"))
Qx <-prettyQspray(Px, "x")
## [1] "x^4 - x^2 + 3/16"
prettyQspray(Qx, "x")
## [1] "1/2 - 2*x^2"
```

It is easy to see that \(x= \pm 1/2\) are the roots of the second polynomial. And one can check that they are also some roots of the first one. One can conclude that \((-1/2, 1/2)\) and \((1/2, 1/2)\) are some intersection points.

And we’re done.