The hardware and bandwidth for this mirror is donated by METANET, the Webhosting and Full Service-Cloud Provider.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]metanet.ch.
mpoly is a simple collection of tools to help deal
with multivariate polynomials symbolically and functionally in
R. Polynomials are defined with the mp()
function:
library("mpoly")
# Registered S3 methods overwritten by 'ggplot2':
# method from
# [.quosures rlang
# c.quosures rlang
# print.quosures rlang
mp("x + y")
# x + y
mp("(x + 4 y)^2 (x - .25)")
# x^3 - 0.25 x^2 + 8 x^2 y - 2 x y + 16 x y^2 - 4 y^2
Term orders are available with the reorder function:
<- mp("(x + y)^2 (1 + x)"))
(p # x^3 + x^2 + 2 x^2 y + 2 x y + x y^2 + y^2
reorder(p, varorder = c("y","x"), order = "lex")
# y^2 x + y^2 + 2 y x^2 + 2 y x + x^3 + x^2
reorder(p, varorder = c("x","y"), order = "glex")
# x^3 + 2 x^2 y + x y^2 + x^2 + 2 x y + y^2
Vectors of polynomials (mpolyList
’s) can be specified in
the same way:
mp(c("(x+y)^2", "z"))
# x^2 + 2 x y + y^2
# z
You can extract pieces of polynoimals using the standard
[
operator, which works on its terms:
1]
p[# x^3
1:3]
p[# x^3 + x^2 + 2 x^2 y
-1]
p[# x^2 + 2 x^2 y + 2 x y + x y^2 + y^2
There are also many other functions that can be used to piece apart polynomials, for example the leading term (default lex order):
LT(p)
# x^3
LC(p)
# [1] 1
LM(p)
# x^3
You can also extract information about exponents:
exponents(p)
# [[1]]
# x y
# 3 0
#
# [[2]]
# x y
# 2 0
#
# [[3]]
# x y
# 2 1
#
# [[4]]
# x y
# 1 1
#
# [[5]]
# x y
# 1 2
#
# [[6]]
# x y
# 0 2
multideg(p)
# x y
# 3 0
totaldeg(p)
# [1] 3
monomials(p)
# x^3
# x^2
# 2 x^2 y
# 2 x y
# x y^2
# y^2
Arithmetic is defined for both polynomials (+
,
-
, *
and ^
)…
<- mp("x + y")
p1
<- mp("x - y")
p2
+ p2
p1 # 2 x
- p2
p1 # 2 y
* p2
p1 # x^2 - y^2
^2
p1# x^2 + 2 x y + y^2
… and vectors of polynomials:
<- mp(c("x", "y")))
(ps1 # x
# y
<- mp(c("2 x", "y + z")))
(ps2 # 2 x
# y + z
+ ps2
ps1 # 3 x
# 2 y + z
- ps2
ps1 # -1 x
# -1 z
* ps2
ps1 # 2 x^2
# y^2 + y z
You can compute derivatives easily:
<- mp("x + x y + x y^2")
p
deriv(p, "y")
# x + 2 x y
gradient(p)
# y^2 + y + 1
# 2 y x + x
You can turn polynomials and vectors of polynomials into functions
you can evaluate with as.function()
. Here’s a basic example
using a single multivariate polynomial:
<- as.function(mp("x + 2 y")) # makes a function with a vector argument
f # f(.) with . = (x, y)
f(c(1,1))
# [1] 3
<- as.function(mp("x + 2 y"), vector = FALSE) # makes a function with all arguments
f # f(x, y)
f(1, 1)
# [1] 3
Here’s a basic example with a vector of multivariate polynomials:
<- mp(c("x", "2 y")))
(p # x
# 2 y
<- as.function(p)
f # f(.) with . = (x, y)
f(c(1,1))
# [1] 1 2
<- as.function(p, vector = FALSE)
f # f(x, y)
f(1, 1)
# [1] 1 2
Whether you’re working with a single multivariate polynomial or a
vector of them (mpolyList
), if it/they are actually
univariate polynomial(s), the resulting function is vectorized. Here’s
an example with a single univariate polynomial.
<- as.function(mp("x^2"))
f # f(.) with . = x
f(1:3)
# [1] 1 4 9
<- matrix(1:4, 2))
(mat # [,1] [,2]
# [1,] 1 3
# [2,] 2 4
f(mat) # it's vectorized properly over arrays
# [,1] [,2]
# [1,] 1 9
# [2,] 4 16
Here’s an example with a vector of univariate polynomials:
<- mp(c("t", "t^2")))
(p # t
# t^2
<- as.function(p)
f f(1)
# [1] 1 1
f(1:3)
# [,1] [,2]
# [1,] 1 1
# [2,] 2 4
# [3,] 3 9
You can use this to visualize a univariate polynomials like this:
library("tidyverse"); theme_set(theme_classic())
<- as.function(mp("(x-2) x (x+2)"))
f # f(.) with . = x
<- seq(-2.5, 2.5, .1)
x
qplot(x, f(x), geom = "line")
For multivariate polynomials, it’s a little more complicated:
<- as.function(mp("x^2 - y^2"))
f # f(.) with . = (x, y)
<- seq(-2.5, 2.5, .1)
s <- expand.grid(x = s, y = s)
df $f <- apply(df, 1, f)
dfqplot(x, y, data = df, geom = "raster", fill = f)
Using tidyverse-style coding
(install tidyverse packages with
install.packages("tidyverse")
), this looks a bit
cleaner:
<- as.function(mp("x^2 - y^2"), vector = FALSE)
f # f(x, y)
seq(-2.5, 2.5, .1) %>%
list("x" = ., "y" = .) %>%
cross_df() %>%
mutate(f = f(x, y)) %>%
ggplot(aes(x, y, fill = f)) +
geom_raster()
Grobner bases are no longer implemented in mpoly; they’re now in m2r.
# polys <- mp(c("t^4 - x", "t^3 - y", "t^2 - z"))
# grobner(polys)
Homogenization and dehomogenization:
<- mp("x + 2 x y + y - z^3"))
(p # x + 2 x y + y - z^3
<- homogenize(p))
(hp # x t^2 + 2 x y t + y t^2 - z^3
dehomogenize(hp, "t")
# x + 2 x y + y - z^3
homogeneous_components(p)
# x + y
# 2 x y
# -1 z^3
mpoly can make use of many pieces of the
polynom and orthopolynom packages with
as.mpoly()
methods. In particular, many special polynomials
are available.
You can construct Chebyshev polynomials as follows:
chebyshev(1)
# Loading required package: polynom
#
# Attaching package: 'polynom'
# The following object is masked from 'package:mpoly':
#
# LCM
# x
chebyshev(2)
# -1 + 2 x^2
chebyshev(0:5)
# 1
# x
# 2 x^2 - 1
# 4 x^3 - 3 x
# 8 x^4 - 8 x^2 + 1
# 16 x^5 - 20 x^3 + 5 x
And you can visualize them:
<- seq(-1, 1, length.out = 201); N <- 5
s <- chebyshev(0:N))
(chebPolys # 1
# x
# 2 x^2 - 1
# 4 x^3 - 3 x
# 8 x^4 - 8 x^2 + 1
# 16 x^5 - 20 x^3 + 5 x
<- as.function(chebPolys)(s) %>% cbind(s, .) %>% as.data.frame()
df names(df) <- c("x", paste0("T_", 0:N))
<- df %>% gather(degree, value, -x)
mdf qplot(x, value, data = mdf, geom = "path", color = degree)
<- seq(-1, 1, length.out = 201); N <- 5
s <- jacobi(0:N, 2, 2))
(jacPolys # 1
# 5 x
# 17.5 x^2 - 2.5
# 52.5 x^3 - 17.5 x
# 144.375 x^4 - 78.75 x^2 + 4.375
# 375.375 x^5 - 288.75 x^3 + 39.375 x
<- as.function(jacPolys)(s) %>% cbind(s, .) %>% as.data.frame
df names(df) <- c("x", paste0("P_", 0:N))
<- df %>% gather(degree, value, -x)
mdf qplot(x, value, data = mdf, geom = "path", color = degree) +
coord_cartesian(ylim = c(-25, 25))
<- seq(-1, 1, length.out = 201); N <- 5
s <- legendre(0:N))
(legPolys # 1
# x
# 1.5 x^2 - 0.5
# 2.5 x^3 - 1.5 x
# 4.375 x^4 - 3.75 x^2 + 0.375
# 7.875 x^5 - 8.75 x^3 + 1.875 x
<- as.function(legPolys)(s) %>% cbind(s, .) %>% as.data.frame
df names(df) <- c("x", paste0("P_", 0:N))
<- df %>% gather(degree, value, -x)
mdf qplot(x, value, data = mdf, geom = "path", color = degree)
<- seq(-3, 3, length.out = 201); N <- 5
s <- hermite(0:N))
(hermPolys # 1
# x
# x^2 - 1
# x^3 - 3 x
# x^4 - 6 x^2 + 3
# x^5 - 10 x^3 + 15 x
<- as.function(hermPolys)(s) %>% cbind(s, .) %>% as.data.frame
df names(df) <- c("x", paste0("He_", 0:N))
<- df %>% gather(degree, value, -x)
mdf qplot(x, value, data = mdf, geom = "path", color = degree)
<- seq(-5, 20, length.out = 201); N <- 5
s <- laguerre(0:N))
(lagPolys # 1
# -1 x + 1
# 0.5 x^2 - 2 x + 1
# -0.1666667 x^3 + 1.5 x^2 - 3 x + 1
# 0.04166667 x^4 - 0.6666667 x^3 + 3 x^2 - 4 x + 1
# -0.008333333 x^5 + 0.2083333 x^4 - 1.666667 x^3 + 5 x^2 - 5 x + 1
<- as.function(lagPolys)(s) %>% cbind(s, .) %>% as.data.frame
df names(df) <- c("x", paste0("L_", 0:N))
<- df %>% gather(degree, value, -x)
mdf qplot(x, value, data = mdf, geom = "path", color = degree) +
coord_cartesian(ylim = c(-25, 25))
Bernstein
polynomials are not in polynom or
orthopolynom but are available in
mpoly with bernstein()
:
bernstein(0:4, 4)
# x^4 - 4 x^3 + 6 x^2 - 4 x + 1
# -4 x^4 + 12 x^3 - 12 x^2 + 4 x
# 6 x^4 - 12 x^3 + 6 x^2
# -4 x^4 + 4 x^3
# x^4
<- seq(0, 1, length.out = 101)
s <- 5 # number of bernstein polynomials to plot
N <- bernstein(0:N, N))
(bernPolys # -1 x^5 + 5 x^4 - 10 x^3 + 10 x^2 - 5 x + 1
# 5 x^5 - 20 x^4 + 30 x^3 - 20 x^2 + 5 x
# -10 x^5 + 30 x^4 - 30 x^3 + 10 x^2
# 10 x^5 - 20 x^4 + 10 x^3
# -5 x^5 + 5 x^4
# x^5
<- as.function(bernPolys)(s) %>% cbind(s, .) %>% as.data.frame
df names(df) <- c("x", paste0("B_", 0:N))
<- df %>% gather(degree, value, -x)
mdf qplot(x, value, data = mdf, geom = "path", color = degree)
You can use the bernstein_approx()
function to compute
the Bernstein polynomial approximation to a function. Here’s an
approximation to the standard normal density:
<- bernstein_approx(dnorm, 15, -1.25, 1.25)
p round(p, 4)
# -0.1624 x^2 + 0.0262 x^4 - 0.002 x^6 + 0.0001 x^8 + 0.3796
<- seq(-3, 3, length.out = 101)
x <- data.frame(
df x = rep(x, 2),
y = c(dnorm(x), as.function(p)(x)),
which = rep(c("actual", "approx"), each = 101)
)# f(.) with . = x
qplot(x, y, data = df, geom = "path", color = which)
You can construct Bezier polynomials
for a given collection of points with bezier()
:
<- data.frame(x = c(-1,-2,2,1), y = c(0,1,1,0))
points <- bezier(points))
(bezPolys # -10 t^3 + 15 t^2 - 3 t - 1
# -3 t^2 + 3 t
And viewing them is just as easy:
<- as.function(bezPolys)(s) %>% as.data.frame
df
ggplot(aes(x = x, y = y), data = df) +
geom_point(data = points, color = "red", size = 4) +
geom_path(data = points, color = "red", linetype = 2) +
geom_path(size = 2)
Weighting is available also:
<- data.frame(x = c(1,-2,2,-1), y = c(0,1,1,0))
points <- bezier(points))
(bezPolys # -14 t^3 + 21 t^2 - 9 t + 1
# -3 t^2 + 3 t
<- as.function(bezPolys, weights = c(1,5,5,1))(s) %>% as.data.frame
df
ggplot(aes(x = x, y = y), data = df) +
geom_point(data = points, color = "red", size = 4) +
geom_path(data = points, color = "red", linetype = 2) +
geom_path(size = 2)
To make the evaluation of the Bezier polynomials stable,
as.function()
has a special method for Bezier polynomials
that makes use of de
Casteljau’s algorithm. This allows bezier()
to be used
as a smoother:
<- seq(0, 1, length.out = 201)
s <- as.function(bezier(cars))(s) %>% as.data.frame
df qplot(speed, dist, data = cars) +
geom_path(data = df, color = "red")
I’m starting to put in methods for some other R functions:
set.seed(1)
<- 101
n <- data.frame(x = seq(-5, 5, length.out = n))
df $y <- with(df, -x^2 + 2*x - 3 + rnorm(n, 0, 2))
df
<- lm(y ~ x + I(x^2), data = df)
mod <- mod %>% as.mpoly %>% round)
(p # 1.983 x - 1.01 x^2 - 2.709
qplot(x, y, data = df) +
stat_function(fun = as.function(p), colour = 'red')
# f(.) with . = x
<- seq(-5, 5, length.out = n)
s <- expand.grid(x = s, y = s) %>%
df mutate(z = x^2 - y^2 + 3*x*y + rnorm(n^2, 0, 3))
<- lm(z ~ poly(x, y, degree = 2, raw = TRUE), data = df))
(mod #
# Call:
# lm(formula = z ~ poly(x, y, degree = 2, raw = TRUE), data = df)
#
# Coefficients:
# (Intercept)
# -0.070512
# poly(x, y, degree = 2, raw = TRUE)1.0
# -0.004841
# poly(x, y, degree = 2, raw = TRUE)2.0
# 1.005307
# poly(x, y, degree = 2, raw = TRUE)0.1
# 0.001334
# poly(x, y, degree = 2, raw = TRUE)1.1
# 3.003755
# poly(x, y, degree = 2, raw = TRUE)0.2
# -0.999536
as.mpoly(mod)
# -0.004840798 x + 1.005307 x^2 + 0.001334122 y + 3.003755 x y - 0.9995356 y^2 - 0.07051218
From CRAN: install.packages("mpoly")
From Github (dev version):
# install.packages("devtools")
::install_github("dkahle/mpoly") devtools
This material is based upon work partially supported by the National Science Foundation under Grant No. 1622449.
These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.