# The ‘ratioOfQsprays’ package

Stéphane Laurent 2024-04-25

Fractions of multivariate polynomials with rational coefficients.

The qspray package allows arithmetic (and more) on multivariate polynomials with rational coefficients. Based on this one, the ratioOfQsprays package allows to manipulate fractions of multivariate polynomials with rational coefficients.

These notes about the ratioOfQsprays package assume that the reader is a bit familiar with the qspray package.

## Creating a `ratioOfQsprays`

A `ratioOfQsprays` object represents a fraction of two multivariate polynomial with rational coefficients. Such polynomials are represented by `qspray` objects. The easiest way to create a `ratioOfQsprays` is to introduce the variables of the polynomials with the `qlone` function (from the qspray package), and then to build a `qspray` numerator and a `qspray` denominator with the arithmetic operations. For example:

``````library(ratioOfQsprays)
f <- function(x1, x2, x3) {
(2*x1^2 + x2*x3) / (4*x1 - 3*x3 + 1)
}
# variables:
x1 <- qlone(1)
x2 <- qlone(2)
x3 <- qlone(3)
# the 'ratioOfQsprays':
( roq <- f(x1, x2, x3) )
## [ 2*x^2 + y.z ]  %//%  [ 4*x - 3*z + 1 ]``````

Arithmetic on `ratioOfQsprays` objects is available:

``````roq^2
## [ 4*x^4 + 4*x^2.y.z + y^2.z^2 ]  %//%  [ 16*x^2 - 24*x.z + 8*x + 9*z^2 - 6*z + 1 ]
roq - roq
## [ 0 ]
1 / roq
## [ 4*x - 3*z + 1 ]  %//%  [ 2*x^2 + y.z ]
2*roq + (x2 + x3)/x1
## [ 4*x^3 + 2*x.y.z + 4*x.y + 4*x.z - 3*y.z + y - 3*z^2 + z ]  %//%  [ 4*x^2 - 3*x.z + x ]``````

You don’t like my quotient bar `%//%`? Be patient, we will see how to change it later. I adopted this large quotient bar because it is more easy to find it than a single slash `/` in a `ratioOfQsprays` having a long expression.

Rational numbers and `qspray` polynomials are coercible to `ratioOfQsprays` objects, and then you can also perform arithmetic operations between a `ratioOfQsprays` and such an object:

``````2 * roq
## [ 4*x^2 + 2*y.z ]  %//%  [ 4*x - 3*z + 1 ]
"1/2" * roq
## [ x^2 + 1/2*y.z ]  %//%  [ 4*x - 3*z + 1 ]
roq + gmp::as.bigq("7/3")
## [ 2*x^2 + 28/3*x + y.z - 7*z + 7/3 ]  %//%  [ 4*x - 3*z + 1 ]
x1 + roq + x3^2
## [ 6*x^2 + 4*x.z^2 - 3*x.z + x + y.z - 3*z^3 + z^2 ]  %//%  [ 4*x - 3*z + 1 ]``````

The result of an arithmetic operation is always an irreducible fraction. To perform this step, the C++ library CGAL is used to compute a greatest common divisor of the numerator and the denominator of the possibly non-reduced fraction resulting from the arithmetic operation, and then to divide both of them by this greatest common divisor. This is very efficient in general.

## Evaluating a `ratioOfQsprays`

Use `evalRatioOfQsprays` to evaluate a `ratioOfQsprays`. This function returns a `bigq` number:

``````library(gmp) # rational numbers
x <- c("4", "3", "2/5")
evalRatioOfQsprays(roq, x)
## Big Rational ('bigq') :
## [1] 166/79
x <- as.bigq(x)
evalRatioOfQsprays(roq, x)
## Big Rational ('bigq') :
## [1] 166/79
f(x[1], x[2], x[3])
## Big Rational ('bigq') :
## [1] 166/79``````

It is also possible to substitute some values to only a subset of the variables, with the help of the function `substituteRatioOfQsprays`. You have to indicate the variables you don’t want to replace with `NA`:

``````x <- c(NA, "3", "2/5")
substituteRatioOfQsprays(roq, x)
## [ 2*x^2 + 6/5 ]  %//%  [ 4*x - 1/5 ]
x <- as.bigq(x)
f(x1, x[2], x[3])
## [ 2*x^2 + 6/5 ]  %//%  [ 4*x - 1/5 ]``````

And it is possible to convert a `ratioOfQsprays` to a function which is evaluated by Ryacas:

``````fyac <- as.function(roq)
fyac("4", "3", "2/5") # = evalRatioOfQsprays(roq, c("4", "3", "2/5"))
## [1] "166/79"``````

Actually you can pass some literal variables to this function:

``````fyac("x", "3", "2/5") # = substituteRatioOfQsprays(roq, c(NA, "3", "2/5"))
## [1] "(2*(5*x^2+3))/(20*x-1)"
fyac("x", "y", "z")   # = roq
## [1] "(y*z+2*x^2)/(4*x-3*z+1)"
fyac("x", "x", "x")
## [1] "(3*x^2)/(x+1)"``````

Complex numbers and allowed; the imaginary unit is denoted by `I`. See the Yacas documentation for more information.

``````fyac("Sqrt(2)", "2 + 2*I", "3")
## [1] "Complex(10/(Sqrt(32)-8),6/(Sqrt(32)-8))"``````

You can get numerical approximations by setting the option `N=TRUE` in `as.function`:

``````fyacN <- as.function(roq, N = TRUE)
fyacN("4", "3", "2/5")
## [1] 2.101266
fyacN("x", "3", "2/5")
## expression((2 * (5 * x^2 + 3))/(20 * x - 1))
fyacN("Sqrt(2)", "2 + 2*I", "3")
## [1] -4.267767-2.56066i``````

## Querying a `ratioOfQsprays`

A couple of functions to query a `ratioOfQsprays` are available:

``````getNumerator(roq)
## 2*x^2 + y.z
getDenominator(roq)
## 4*x - 3*z + 1
numberOfVariables(roq)
## [1] 3
isConstant(roq)
## [1] FALSE
isConstant(roq / roq)
## [1] TRUE
isUnivariate(roq)
## [1] FALSE
isUnivariate(x1 / (x1^2 + 1))
## [1] TRUE
isPolynomial(roq)
## [1] FALSE
isPolynomial((x1^2 - x2^2) / (x1 - x2))
## [1] TRUE``````

## Showing a `ratioOfQsprays`

As you have seen, the variables of `roq` are denoted by `x`, `y`, `z`. This is the default way of printing a `ratioOfQsprays` which has no more than three variables. If it has more than three variables, then they are denoted by `x1`, `x2`, `x3`, …:

``````x4 <- qlone(4)
roq / x4
## [ 2*x1^2 + x2.x3 ]  %//%  [ 4*x1.x4 - 3*x3.x4 + x4 ]``````

It is possible to control the way a `ratioOfQsprays` is printed. For example, let’s say you want to print `roq` by using `a1`, `a2`, `a3` for the variables and you want to change the symbol for the quotient bar:

``````showRatioOfQspraysOption(roq, "x") <- "a"
showRatioOfQspraysOption(roq, "quotientBar") <- " / "
roq
## [ 2*a1^2 + a2.a3 ] / [ 4*a1 - 3*a3 + 1 ]``````

Now, if you perform an arithmetic operation between `roq` at first position and an another `ratioOfQsprays`, these show options are passed to the result if possible:

``````roq + (x1 + 1)/x2
## [ 2*a1^2.a2 + 4*a1^2 - 3*a1.a3 + 5*a1 + a2^2.a3 - 3*a3 + 1 ] / [ 4*a1.a2 - 3*a2.a3 + a2 ]``````

If you perform an arithmetic operation between `roq` and an object coercible to a `ratioOfQsprays` object but which is not a `ratioOfQsprays` object, such as a `bigq` number or a `qspray` object, the show options of `roq` are passed to the result, even if `roq` is not at the first position:

``````x1 * roq
## [ 2*a1^3 + a1.a2.a3 ] / [ 4*a1 - 3*a3 + 1 ]``````

An obvious example of a situation in which it is not always possible to transfer the show options is when you use three letters for the variables, e.g.

``````showRatioOfQspraysOption(roq, "showQspray") <- showQsprayXYZ(c("A", "B", "C"))
roq
## [ 2*A^2 + B.C ] / [ 4*A - 3*C + 1 ]``````

but then you add to `roq` a `ratioOfQsprays` containing the fourth variable:

``````roq + x4/(x4 + 1)
## [ 2*A1^2.A4 + 2*A1^2 + 4*A1.A4 + A2.A3.A4 + A2.A3 - 3*A3.A4 + A4 ] / [ 4*A1.A4 + 4*A1 - 3*A3.A4 - 3*A3 + A4 + 1 ]``````

Obviously it is not possible to denote the resulting fraction of polynomials with the letters `A`, `B` and `C`. The solution I adopted consists in taking the first of these letters and to index it. The same method is used for the `qspray` polynomials.

## Transforming a `ratioOfQsprays`

Let’s take a `ratioOfQsprays` fraction of polynomials:

``````f <- function(x, y, z) {
(2*x^2 + y*z) / (4*x - 3*z + 1)
}
x <- qlone(1); y <- qlone(2); z <- qlone(3)
roq <- f(x, y, z)``````

You can differentiate it:

``````derivRatioOfQsprays(roq, 2) # derivative w.r.t. y
## [ -3*z ]  %//%  [ -12*x + 9*z - 3 ]``````

You can permute its variables:

``````swapVariables(roq, 2, 3) == f(x, z, y)
## [1] TRUE``````

You can perform some polynomial changes of its variables:

``````changeVariables(roq, list(x+1, y^2, x+y+z)) == f(x+1, y^2, x+y+z)
## [1] TRUE``````