https://github.com/stla/symbolicqspray
Multivariate polynomials whose coefficients are fractions of multivariate polynomials.
https://github.com/stla/symbolicqspray
multivariate-polynomials r symbolic-computation
Last synced: about 1 year ago
JSON representation
Multivariate polynomials whose coefficients are fractions of multivariate polynomials.
- Host: GitHub
- URL: https://github.com/stla/symbolicqspray
- Owner: stla
- Created: 2024-04-05T23:37:40.000Z (about 2 years ago)
- Default Branch: main
- Last Pushed: 2024-04-13T19:01:25.000Z (about 2 years ago)
- Last Synced: 2024-04-14T00:24:36.841Z (about 2 years ago)
- Topics: multivariate-polynomials, r, symbolic-computation
- Language: R
- Homepage:
- Size: 122 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.Rmd
Awesome Lists containing this project
README
---
title: "The 'symbolicQspray' package"
author: "Stéphane Laurent"
date: "`r Sys.Date()`"
output: github_document
editor_options:
chunk_output_type: console
---
***Multivariate polynomials with symbolic parameters.***
[](https://github.com/stla/symbolicQspray/actions/workflows/R-CMD-check.yaml)
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE, collapse = TRUE, message = FALSE)
```
___
These notes about the **symbolicQspray** package assume that the reader is a
bit familiar with the [**qspray** package][qspray] and with the
[**ratioOfQsprays** package][ratioOfQsprays].
A `symbolicQspray` object represents a multivariate polynomial whose
coefficients are fractions of polynomials with rational coefficients.
Actually (see our discussion in the next section), a `symbolicQspray` object
represents a *multivariate polynomial with parameters*. The parameters are
the variables of the fractions of polynomials, and so they are symbolically
represented.
To construct a `symbolicQspray` polynomial, use `qlone` (from the **qspray**
package) to introduce the parameters and use `Qlone` to introduce the variables
of the polynomial:
```{r}
library(symbolicQspray)
f <- function(a1, a2, X1, X2, X3) {
(a1/(a2^2+1)) * X1^2*X2 + (a2+1) * X3 + a1/a2
}
# parameters, the variables occurring in the coefficients:
a1 <- qlone(1)
a2 <- qlone(2)
# variables:
X1 <- Qlone(1)
X2 <- Qlone(2)
X3 <- Qlone(3)
# the 'symbolicQspray':
( Qspray <- f(a1, a2, X1, X2, X3) )
```
The fractions of polynomials such as the first coefficient `a1/(a2^2+1)`
in the above example are [**ratioOfQsprays**][ratioOfQsprays] objects,
and the numerator and the denominator of a `ratioOfQsprays` are
[**qspray**][qspray] objects.
Arithmetic on `symbolicQspray` objects is available:
```{r}
Qspray^2
Qspray - Qspray
(Qspray - 1)^2
Qspray^2 - 2*Qspray + 1
```
## Evaluating a `symbolicQspray`
Substituting the "exterior" variables (the variables occurring in the ratios of
polynomials, also called the *parameters* - see below) yields a `qspray` object:
```{r}
a <- c(2, "3/2")
( qspray <- evalSymbolicQspray(Qspray, a = a) )
```
Substituting the "main" variables yields a `ratioOfQsprays` object:
```{r}
X <- c(4, 3, "2/5")
( ratioOfQsprays <- evalSymbolicQspray(Qspray, X = X) )
```
There is a discutable point here. A `symbolicQspray` object represents a
polynomial with `ratioOfQsprays` coefficients. So one could consider
that the polynomial variables `X`, `Y` and `Z` represent some indeterminate
`ratioOfQsprays` fractions, and that it should be possible to replace them
with `ratioOfQsprays` objects. However this is not allowed.
We will discuss that, just after checking the consistency:
```{r}
evalSymbolicQspray(Qspray, a = a, X = X)
evalQspray(qspray, X)
evalRatioOfQsprays(ratioOfQsprays, a)
a <- gmp::as.bigq(a); X <- gmp::as.bigq(X)
f(a[1], a[2], X[1], X[2], X[3])
```
Now let's turn to our promised discussion. Why is replacing the values of the
polynomial variables with some `ratioOfQsprays` objects not allowed?
Actually my motivation to do this package was inspired by the
[**Jack polynomials**][jack]. In the context of Jack polynomials, the variables
`X`, `Y` and `Z` represent indeterminate *numbers*, and the coefficients
are *numbers depending on a parameter* (the Jack parameter), and it turns out
that they are fractions of polynomials of this parameter.
So I consider that a `symbolicQspray` is *not* a polynomial on the field
of fractions of polynomials: I consider it is a polynomial with
*rational coefficients depending on some parameters*.
Also note that evaluating the `ratioOfQsprays` object
`evalSymbolicQspray(Qspray, X = X)` at `a` would make no sense if we took
some `ratioOfQsprays` objects for the values of `X`.
## Querying a `symbolicQspray`
The package provides some functions to perform elementary queries on a
`symbolicQspray`:
```{r, collapse=TRUE}
numberOfVariables(Qspray)
numberOfParameters(Qspray)
numberOfTerms(Qspray)
getCoefficient(Qspray, c(2, 1)) # coefficient of X^2.Y
getConstantTerm(Qspray)
isUnivariate(Qspray)
isConstant(Qspray)
```
## Transforming a `symbolicQspray`
You can differentiate a `symbolicQspray` polynomial:
```{r}
derivSymbolicQspray(Qspray, 2) # derivative w.r.t. Y
```
You can permute its variables:
```{r}
swapVariables(Qspray, 2, 3) == f(a1, a2, X1, X3, X2)
```
You can perform polynomial transformations of its variables:
```{r}
changeVariables(Qspray, list(X1+1, X2^2, X1+X2+X3)) ==
f(a1, a2, X1+1, X2^2, X1+X2+X3)
```
You can also perform polynomial transformations of its parameters:
```{r}
changeParameters(Qspray, list(a1^2, a2^2)) == f(a1^2, a2^2, X1, X2, X3)
```
## Showing a `symbolicQspray`
You can change the way a `symbolicQspray` is printed by using
`showSymbolicQsprayOption`:
```{r, collapse=TRUE}
showSymbolicQsprayOption(Qspray, "a") <- "x"
showSymbolicQsprayOption(Qspray, "showMonomial") <-
showMonomialXYZ(c("A", "B", "C"))
showSymbolicQsprayOption(Qspray, "quotientBar") <- " / "
Qspray
```
When this is possible, the result of an arithmetic operation between two
`symbolicQspray` objects inherits the show options of the first operand:
```{r, collapse=TRUE}
set.seed(421)
( Q <- rSymbolicQspray() ) # a random symbolicQspray
Qspray + Q
```
This behavior is the same as the ones implemented in **qspray** and in
**ratioOfQsprays**. You should be familiar with these two packages in order
to use **symbolicQspray**.
## Application: Jacobi polynomials
The [Jacobi polynomials][jacobi] are univariate polynomials depending on two
parameters that we will denote by `alpha` and `beta`. They are implemented in
this package:
```{r}
JP <- JacobiPolynomial(2)
isUnivariate(JP)
numberOfParameters(JP)
showSymbolicQsprayOption(JP, "showRatioOfQsprays") <-
showRatioOfQspraysXYZ(c("alpha", "beta"))
JP
```
The implementation constructs these polynomials by using the
[recurrence relation][jacobirecurrence].
This is a child game, one just has to copy the first two terms and this
recurrence relation:
```{r, eval=FALSE}
JacobiPolynomial <- function(n) {
stopifnot(isPositiveInteger(n))
if(n == 0) {
Qone()
} else if(n == 1) {
alpha <- qlone(1)
beta <- qlone(2)
X <- Qlone(1)
(alpha + 1) + (alpha + beta + 2) * (X - 1)/2
} else {
alpha <- qlone(1)
beta <- qlone(2)
X <- Qlone(1)
a <- n + alpha
b <- n + beta
c <- a + b
K <- 2 * n * (c - n) * (c - 2)
lambda1 <- ((c - 1) * (c * (c - 2) * X + (a - b) * (c - 2*n))) / K
lambda2 <- (2 * (a - 1) * (b - 1) * c) / K
(lambda1 * JacobiPolynomial(n - 1) - lambda2 * JacobiPolynomial(n - 2))
}
}
```
It is clearly visible from the recurrence relation that the coefficients of the
Jacobi polynomials are indeed fractions of polynomials in `alpha` and `beta`.
But they actually are *polynomials* in `alpha` and `beta`. Actually I don't
know, this is a conjecture I made because I observed this fact for some small
values of `n`. We can check it with the function
`hasPolynomialCoefficientsOnly`:
```{r}
JP <- JacobiPolynomial(7)
hasPolynomialCoefficientsOnly(JP)
```
Up to a factor, the [Gegenbauer polynomials][gegenbauer] with parameter `alpha`
coincide with the Jacobi polynomials with parameters `alpha - 1/2` and
`alpha - 1/2`. Let's derive them from the Jacobi polynomials, as an exercise.
The factor can be implemented as follows (see Wikipedia for its formula):
```{r}
risingFactorial <- function(theta, n) {
toMultiply <- c(theta, lapply(seq_len(n-1), function(i) theta + i))
Reduce(`*`, toMultiply)
}
theFactor <- function(alpha, n) {
risingFactorial(2*alpha, n) / risingFactorial((2*alpha + 1)/2, n)
}
```
Now let's apply the formula given in the Wikipedia article:
```{r}
GegenbauerPolynomial <- function(n) {
alpha <- qlone(1)
P <- changeParameters(
JacobiPolynomial(n), list(alpha - "1/2", alpha - "1/2")
)
theFactor(alpha, n) * P
}
```
Let's check that the recurrence relation given in the Wikipedia article is
fulfilled:
```{r}
n <- 5
alpha <- qlone(1)
X <- Qlone(1)
(n + 1) * GegenbauerPolynomial(n+1) ==
2*(n + alpha) * X * GegenbauerPolynomial(n) -
(n + 2*alpha - 1) * GegenbauerPolynomial(n-1)
```
## Application to Jack polynomials
The **symbolicQspray** package is used in the [**jack** package][jack] to
compute the Jack polynomials with a symbolic Jack parameter. The Jack
polynomials exactly fit to the polynomials represented by the `symbolicQspray`
objects: their coefficients are fractions of polynomials by definition, of one
variable: the Jack parameter.
[qspray]: https://github.com/stla/qspray "the 'qspray' package on Github"
[ratioOfQsprays]: https://github.com/stla/ratioOfQsprays "the 'ratioOfQsprays' package on Github"
[jack]: https://github.com/stla/jackR "the 'jack' package on Github"
[gegenbauer]: https://en.wikipedia.org/wiki/Gegenbauer_polynomials "Gegenbauer polynomials on Wikipedia"
[jacobi]: https://en.wikipedia.org/wiki/Jacobi_polynomials "Jacobi polynomials on Wikipedia"
[jacobirecurrence]: https://en.wikipedia.org/wiki/Jacobi_polynomials#Recurrence_relations "recurrence relation between Jacobi polynomials"