R/polyxtra.R

Defines functions LCM.polynomial LCM GCD.polynomial GCD .LCM2 .GCD2 .degree .is_zero_polynomial summary.polynomial solve.polynomial print.summary.polynomial predict.polynomial poly.from.zeros poly.calc points.polynomial plot.polynomial monic lines.polynomial integral.polynomial integral deriv.polynomial coef.polynomial change.origin

Documented in change.origin coef.polynomial deriv.polynomial GCD GCD.polynomial integral integral.polynomial LCM LCM.polynomial lines.polynomial monic plot.polynomial points.polynomial poly.calc poly.from.zeros predict.polynomial print.summary.polynomial solve.polynomial summary.polynomial

change.origin <- function(p, o) {
  if (!is.polynomial(p))
    stop(paste("\"", deparse(substitute(p)), "\"", " is not a polynomial"))
  o <- unclass(o[1])
  r <- predict(p, o)
  m <- 1
  p <- deriv(p)
  while (p != 0) {
    r <- c(r, predict(p, o))
    m <- m + 1
    p <- polynomial(unclass(deriv(p))/m)
  }
  polynomial(r)
}

coef.polynomial <- function(object, ...) {
  as.vector(object)
}

deriv.polynomial <- function(expr, ...) {
  expr <- unclass(expr)
  if (length(expr) == 1)
    return(polynomial(0))
  expr <- expr[-1]
  polynomial(expr * seq(along = expr))
}

integral <- function(expr, ...) {
  UseMethod("integral")
}

integral.polynomial <- function(expr, limits = NULL, ...) {
  expr <- unclass(expr)
  p <- polynomial(c(0, expr/seq(along = expr)))
  if (is.null(limits))
    p else diff(predict(p, limits))
}

lines.polynomial <- function(x, len = 1000, xlim = NULL, ylim = NULL, ...) {
  p <- x  # generic/method
  if (is.null(xlim))
    xlim <- par("usr")[1:2]
  if (is.null(ylim))
    ylim <- par("usr")[3:4]
  x <- seq(xlim[1], xlim[2], len = len)
  y <- predict(p, x)
  y[y <= ylim[1] | y >= ylim[2]] <- NA
  lines(x, y, ...)
}

monic <- function(p) {
  p <- unclass(p)
  if (all(p == 0)) {
    warning("the zero polynomial has no monic form")
    return(polynomial(0))
  }
  polynomial(p/p[length(p)])
}

plot.polynomial <- function(x, xlim = 0:1, ylim = range(Px), type = "l", len = 1000,
                            ..., xlab = "x", ylab = "P(x)") {
  p <- x  # generic/method
  if (missing(xlim))
    xlim <- range(c(0, Re(unlist(summary(p)))))
  if (any(is.na(xlim))) {
    warning("summary of polynomial fails. Using nominal xlim")
    xlim <- 0:1
  }
  if (diff(xlim) == 0)
    xlim <- xlim + c(-1, 1)/2
  if (length(xlim) > 2)
    x <- xlim else {
    eps <- diff(xlim)/100
    xlim <- xlim + c(-eps, eps)
    x <- seq(xlim[1], xlim[2], len = len)
  }
  Px <- predict(p, x)
  if (!missing(ylim))
    Px[Px < ylim[1]] <- Px[Px > ylim[2]] <- NA
  plot(x, Px, type = type, xlim = xlim, ylim = ylim,
       ..., xlab = xlab, ylab = ylab)
  grid(lty = "dashed")
  lines(x, Px, type = type, ...)
}

points.polynomial <- function(x, length = 100, ...) {
  p <- x  # generic/method
  pu <- par("usr")
  x <- seq(pu[1], pu[2], len = length)
  y <- predict(p, x)
  out <- y <= pu[3] | y >= pu[4]
  y[out] <- NA
  points(x, y, ...)
}

poly.calc <- function(x, y, tol = sqrt(.Machine$double.eps), lab = dimnames(y)[[2]]) {
  if (missing(y)) {
    p <- 1
    for (xi in x) {
      p <- c(0, p) - c(xi * p, 0)
    }
    return(polynomial(p))
  }
  if (is.matrix(y)) {
    if (length(x) != nrow(y))
      stop("x and y are inconsistent in size")
    lis <- list()
    if (is.null(lab))
      lab <- paste("p", 1:(dim(y)[2]), sep = "")
    for (i in 1:dim(y)[2]) lis[[lab[i]]] <- Recall(x, y[, i], tol)
    return(structure(lis, class = "polylist"))
  }
  if (any(toss <- duplicated(x))) {
    crit <- max(tapply(y, x, function(x) diff(range(x))))
    if (crit > tol)
      warning("some duplicated x-points have inconsistent y-values")
    keep <- !toss
    y <- y[keep]
    x <- x[keep]
  }
  if ((m <- length(x)) != length(y))
    stop("x and y(x) do not match in length!")
  if (m <= 1)
    return(polynomial(y))
  r <- 0
  for (i in 1:m) r <- r + (y[i] * unclass(Recall(x[-i])))/prod(x[i] - x[-i])
  r[abs(r) < tol] <- 0
  polynomial(r)
}

poly.from.zeros <- function(...) {
  poly.calc(unlist(list(...)))
}

poly.from.roots <- poly.from.zeros

poly.from.values <- poly.calc

predict.polynomial <- function(object, newdata, ...) {
  p <- object  # generic/method
  v <- 0
  p <- rev(unclass(p))
  for (pj in p) v <- newdata * v + pj
  v
}

print.summary.polynomial <- function(x, ...) {
  cat("\n Summary information for:\n")
  print(attr(x, "originalPolynomial"))
  cat("\n Zeros:\n")
  print(x$zeros)
  cat("\n Stationary points:\n")
  print(x$stationaryPoints)
  cat("\n Points of inflexion:\n")
  print(x$inflexionPoints)
  invisible(x)
}

solve.polynomial <- function(a, b, ...) {
  if (!missing(b))
    a <- a - b
  a <- unclass(a)
  if (a[1] == 0) {
    z <- rle(a)$lengths[1]
    a <- a[-(1:z)]
    r <- rep(0, z)
  } else {
    r <- numeric(0)
  }
  switch(as.character(length(a)),
         `0` = , `1` = r,
         `2` = sort(c(r, -a[1]/a[2])),
         {
           a <- rev(unclass(a))
           a <- (a/a[1])[-1]
           M <- rbind(-a, cbind(diag(length(a) - 1), 0))
           sort(c(r, eigen(M, symmetric = FALSE, only.values = TRUE)$values))
         })
}

summary.polynomial <- function(object, ...) {
  dp <- deriv(object)
  structure(list(zeros = solve(object),
                 stationaryPoints = solve(dp),
                 inflexionPoints = solve(deriv(dp))),
            class = "summary.polynomial",
    originalPolynomial = object)
}

.is_zero_polynomial <- function(x) {
  identical(x, as.polynomial(0))
}

.degree <- function(x) {
  length(unclass(x)) - 1
}

.GCD2 <- function(x, y) {
  if (.is_zero_polynomial(y)) {
    x
  } else {
    if (.degree(y) == 0) {
      as.polynomial(1)
    } else {
      Recall(y, x%%y)
    }
  }
}

.LCM2 <- function(x, y) {
  if (.is_zero_polynomial(x) || .is_zero_polynomial(y)) {
    return(as.polynomial(0))
  }
  (x/.GCD2(x, y)) * y
}

GCD <- function(...) {
  UseMethod("GCD")
}

GCD.polynomial <- function(...) {
  args <- c.polylist(...)
  if (length(args) < 2)
    stop("Need at least two polynomials.")
  accumulate(.GCD2, args[[1]], args[-1], FALSE)
}

GCD.polylist <- GCD.polynomial

LCM <- function(...) {
  UseMethod("LCM")
}

LCM.polynomial <- function(...) {
  args <- c.polylist(...)
  if (length(args) < 2)
    stop("Need at least two polynomials.")
  accumulate(.LCM2, args[[1]], args[-1], FALSE)
}

LCM.polylist <- LCM.polynomial

Try the polynom package in your browser

Any scripts or data that you put into this service are public.

polynom documentation built on April 11, 2022, 9:05 a.m.