https://github.com/stla/qspray
Multivariate polynomials with rational coefficients.
https://github.com/stla/qspray
gmp polynomials r
Last synced: 6 months ago
JSON representation
Multivariate polynomials with rational coefficients.
- Host: GitHub
- URL: https://github.com/stla/qspray
- Owner: stla
- Created: 2022-12-12T14:06:06.000Z (almost 3 years ago)
- Default Branch: main
- Last Pushed: 2024-08-28T03:25:50.000Z (about 1 year ago)
- Last Synced: 2025-03-28T03:24:24.390Z (7 months ago)
- Topics: gmp, polynomials, r
- Language: R
- Homepage:
- Size: 497 KB
- Stars: 4
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.Rmd
- Changelog: NEWS.md
Awesome Lists containing this project
README
---
title: "The 'qspray' package"
output: github_document
---[](https://github.com/stla/qspray/actions/workflows/R-CMD-check.yaml)
[](https://github.com/stla/qspray/actions/workflows/R-CMD-check-valgrind.yaml)***R package to deal with multivariate polynomials with rational coefficients.***
___
This package is strongly inspired by Robin Hankin's **spray** package.
The C++ implementations are very similar.```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE, collapse = TRUE, message = FALSE)
``````{r}
library(qspray)
```The **qspray** package provides the `qspray` objects, which represent
multivariate polynomials whose coefficients are rational numbers.## Creating a `qspray` polynomial and arithmetic
The easiest way to build a multivariate polynomial with **qspray** is to start
by introducing the generating variables with the help of the `qlone` function
and then to combine them with arithmetic operations:```{r}
x <- qlone(1); y <- qlone(2); z <- qlone(3)
( pol <- 4*x^2 + "1/2"*y - 5*x*y*z/3 )
```I often like to use a function like this:
```{r}
f <- function(x, y, z) {
4*x^2 + y/2 - 5*x*y*z/3
}
f(x, y, z)
```Or maybe you prefer to define the polynomial by giving it as a string:
```{r}
qsprayMaker(string = "4 x^(2) + 1/2 x^(0, 1) - 5/3 x^(1, 1, 1)")
```As you want, but this method is not highly robust. And it is not very easy to
figure out what is the monomial represented by a string such as `"x^(i,j,k)"`
(this is `x^i*y^j*z^k`).Some arithmetic on this polynomial:
```{r}
-pol
2 * pol
pol / 2
"5/3" * pol
pol + 5
pol - gmp::as.bigq("2/5")
pol^2
```Two polynomials can be added and multiplied:
```{r}
pol1 <- pol
pol2 <- pol
pol1 + pol2
pol1 - pol2
pol1 * pol2
```## Evaluating a `qspray`
Use `evalQspray` to evaluate a polynomial for some values of the variables:
```{r}
evalQspray(pol, c("1", "2", "3/2"))
```Alternatively, you can convert the polynomial to a function:
```{r}
g <- as.function(pol)
g("1", "2", "3/2")
```You can pass the strings you want as the arguments of this function:
```{r}
g("x", "y", "z")
g("x+1", "2*x", "y^2")
```The output of `g("x+1", "2*x", "y^2")` is the expression of a bivariate
polynomial. You can get it as a `qspray` polynomial with the help of the
function `changeVariables` (see section **Transforming a `qspray`**).If you want a function returning numerical approximations, use the
option `N=TRUE`:```{r}
h <- as.function(pol, N = TRUE)
h("1", "2", "3/2")
h("x", "y", "z")
h("x+1", "2*x", "y^2")
```You can also perform "partial evaluation" of a `qspray`, that is to say
replacing only certain variables. This is done by using the function
`substituteQspray` and indicating the variables to be kept with `NA`:```{r}
substituteQspray(pol, c("1", NA, "3/2"))
f(gmp::as.bigq(1), y, gmp::as.bigq("3/2"))
g("1", "y", "3/2")
h("1", "y", "3/2")
```## Showing a `qspray`
You can control the way of printing a `qspray` with the help of the function
`showQsprayOption<-`. By default, the monomials of a `qspray` are printed in
the style of `x^2.y.z^3` if there are no more than three variables, otherwise
they are printed in the style of `x1^2.x2.x3^3`:```{r}
set.seed(3141)
( qspray <- rQspray() ) # a random qspray
qspray + qlone(4)^99
```If you want to always use the second way, you can do:
```{r}
showQsprayOption(qspray, "x") <- "x"
qspray
```If you want to restore the way `qspray` objects were printed in previous
versions, you can do```{r}
showQsprayOption(qspray, "showMonomial") <- showMonomialOld()
qspray
```There are three possible show options that can be passed to
`showQsprayOption`:- The most general show option is `"showQspray"`. A `showQspray` function, that
is to say a function appropriate for the `"showQspray"` option, must be
a function which transforms a `qspray` to a string. The package provides
some helper functions to built such functions, like `showQsprayXYZ` and
`showQsprayX1X2X3`. With `showQsprayXYZ`, you can choose the letters you want
to denote the variables:```{r}
f <- showQsprayXYZ(c("A", "B", "C"))
f(qspray)
```With `showQsprayX1X2X3`, you choose only one letter for the variables and they
will be appended with a digit:```{r}
f <- showQsprayX1X2X3("X")
f(qspray)
```Once you have constructed such a function, you pass it as a show option by
doing `showQsprayOption(qspray, "showQspray") <- f`.- The second possible show option is `"showMonomial"`, to control the way the
monomials are printed. Actually in the two above examples of `showQsprayXYZ`
and `showQsprayX1X2X3` we only changed the way the monomials are printed.
Indeed, these two commands are equivalent:
```{r}
showQsprayOption(qspray, "showQspray") <- showQsprayXYZ(c("A", "B", "C"))
showQsprayOption(qspray, "showMonomial") <- showMonomialXYZ(c("A", "B", "C"))
```
and these two commands are equivalent as well:
```{r}
showQsprayOption(qspray, "showQspray") <- showQsprayX1X2X3("X")
showQsprayOption(qspray, "showMonomial") <- showMonomialX1X2X3("X")
```
But the `showQspray` functions allow finer control, e.g. they allow to control
the multiplication symbol which separates a coefficient and a monomial within a
term.- Finally there is the show option `"x"`. Setting this option to a letter `x`:
```{r, eval=FALSE}
showQsprayOption(qspray, "x") <- x
```
is equivalent to:
```{r, eval=FALSE}
showQsprayOption(qspray, "showMonomial") <- showMonomialX1X2X3(x)
```
But `showMonomialX1X2X3` also allows to control the way the individual
powers are collapsed, e.g. `"x^2.y.z^3"` (the default) or `"x^2*y*z^3"`, or
`"x^2yz^3"`. If the dot is nice for you, use the `"x"` option, that's less code
to type.By the way, a `qspray` object is an S4 object with two slots: `powers` and
`coeffs`. The `powers` slot is a list of vector of exponents and the `coeffs`
slot is a character vector, whose each element is coercable to a `bigq`
number by an application of the function `gmp::as.bigq`. The `showMonomial`
functions act only on the `powers` slot.When an arithmetic operation is performed between two `qspray` objects,
the show options of the first one are passed to the result, *if possible*:```{r}
qspray + qlone(4)^99
```For example, this is not possible if you specify only three letters
for the variables and you perform an operation with a `qspray` involving the
fourth variable:```{r}
showQsprayOption(qspray, "showMonomial") <- showMonomialXYZ(c("a", "b", "c"))
qspray
qspray + qlone(4)^99
```## Exact integration over a simplex
The package provides a function which returns the exact value of the
integral of a polynomial with rational coefficients over a simplex whose
vertices have rational Cartesian coordinates:```{r}
# variables
x <- qlone(1); y <- qlone(2); z <- qlone(3)
# polynomial
P <- x^4 + y + 2*x*y^2 - 3*z
# simplex (tetrahedron) vertices
v1 <- c(1, 1, 1)
v2 <- c(2, 2, 3)
v3 <- c(3, 4, 5)
v4 <- c(3, 2, 1)
# simplex
S <- rbind(v1, v2, v3, v4)
# integral
integratePolynomialOnSimplex(P, S)
```## Transforming a `qspray`
Let's take a `qspray` polynomial:
```{r}
f <- function(x, y, z) {
4*x^2 + y/2 - 5*x*y*z/3
}
x <- qlone(1); y <- qlone(2); z <- qlone(3)
P <- f(x, y, z)
```You can get a derivative of this polynomial:
```{r}
derivQspray(P, i = 2) # derivative w.r.t y
```You can permute the variables of this polynomial:
```{r}
swapVariables(P, 1, 3) == f(z, y, x)
```You can perform a change of variables on this polynomial:
```{r}
changeVariables(P, list(x+1, 2*x, y^2)) == f(x+1, 2*x, y^2)
```## Gröbner bases
Finally, let us mention the `groebner` function, which computes a Gröbner
basis of the ideal generated by a list of `qspray` polynomials:```{r}
f <- qsprayMaker(string = "x^(3) - 2 x^(1,1)")
g <- qsprayMaker(string = "x^(2,1) - 2 x^(0,2) + x^(1)")
groebner(list(f, g))
```As an application of Gröbner bases, there is the function `isPolynomialOf`.
This function checks whether a polynomial can be obtained by
substituting the variables of a polynomial with some given polynomials: given a
`qspray` polynomial `Q` and some `qspray` polynomials `P1`, ..., `Pn`, does
there exist a polynomial function `f` such that `Q = f(P1, ..., Pn)`? If this
is true, the `isPolynomialOf` function also returns `f`.## Packages using 'qspray'
There are packages depending on the **qspray** package (some of them are not
on CRAN yet):- [**polyhedralCubature**](https://github.com/stla/polyhedralCubature): this package uses the `integratePolynomialOnSimplex` function to get the exact integral of a multivariate polynomial over a polytope.
- [**jack**](https://github.com/stla/jackR): Jack polynomials.
- [**resultant**](https://github.com/stla/resultant): resultant, subresultants, and
greatest common divisor of two `qspray` polynomials.- [**ratioOfQsprays**](https://github.com/stla/ratioOfQsprays): fractions of
`qspray` polynomials.- [**symbolicQspray**](https://github.com/stla/symbolicQspray): multivariate
polynomials whose coefficients are `ratioOfQsprays` fractions of polynomials;
they represent multivariate polynomials with parameters.## Using the C++ code in another package
The three packages **jack**, **ratioOfQsprays** and **symbolicQspray** use some
C++ code based on the header file of the C++ code of **qspray**. If you want
to use it in your package too, include the following instruction in the
DESCRIPTION file:```yaml
LinkingTo: Rcpp, RcppArmadillo, qspray
```And include the following instruction in your C++ code:
```cpp
#include "qspray.h"
```Then you can use the **qspray** header file in your C++ code by using the
namespace `QSPRAY`.The header file provides the templated class `Qspray`. An object of type
`Qspray` represents a multivariate polynomials whose coefficients are
represented by the objects of the type `T`. For example, multivariate
polynomials with numeric coefficients can be represented by the objects of
type `Qspray` (so I should have chosen another name since `Q` is here
to indicate the field of rational numbers). The class `Qspray` provides the
operators `==`, `!=`, `+`, `-`, `*` and the power for the objects of type
`Qspray` as long as the operators `==`, `!=`, `+`, `-` and `*` are available
for the type `T`. So you don't have to implement the comparison operators nor
the arithmetic operations for the `Qspray` polynomials if you
instantiate this type. The class `Qspray` also provides a function to
calculate derivatives. This class is included in the namespace `QSPRAY` which
also includes a function performing the division of two multivariate
polynomials but it is restricted to polynomials with rational coefficients.
Anyway it would not be a good idea to use the algorithm performed by this
function for polynomials whose coefficients type is not an "exact type",
such as `double`. If you want to use `Qspray` with an exact type `T` and
if you need the division, send me a few words about your use case and I will
see whether I can help. I will probably remove the division from the namespace
`QSPRAY`. I originally included it to use it in the **ratioOfQsprays**
package, but I finally used the division provided by the **CGAL** library
instead, which is faster.A few words about the implementation. The class `Qspray` has only one
member object: an object of type `Polynomial`, which is an alias of
the type `std::unordered_map, T>` (plus a template argument
for the hasher). So a `Polynomial` object is a map whose keys are
`std::vector` objects and whose values are `T` objects. An element of this
map represents a term of the polynomial: a key represents a monomial, e.g. the
vector `{2,1,3}` represents the monomial `x^2*y*z^3`, and the value attached to
this key represents the coefficient of this monomial.
This way to represent a multivariate polynomial has been copied from Robin
Hankin's **spray** package, without which the **qspray** package would have
never existed.