代码之家  ›  专栏  ›  技术社区  ›  Zheyuan Li

对于一个多项式,得到它的所有极值,并通过突出显示所有单调片段来绘制它

  •  3
  • Zheyuan Li  · 技术社区  · 6 年前

    有人问了我这个有趣的问题,我认为值得在这里发布,因为在堆栈溢出方面还没有任何相关的线程。

    n 矢量 pc ,其中 n - 1 对于变量 x

    pc[1] + pc[2] * x + pc[3] * x ^ 2 + ... + pc[n] * x ^ (n - 1)
    

    R核心功能 polyroot 可以找到这个多项式的所有根 复杂的 域名。但通常我们也对极值感兴趣,对于一元函数,局部极小值和极大值交替出现,将函数分解成单调的片段。

    我的问题是:

    1. 真实的 多项式的域?
    2. 如何用双色方案绘制这个多项式:红色代表升序,绿色代表降序?

    最好把它写成一个函数,这样我们就可以很容易地探索/可视化一个多项式。

    例如,考虑5次多项式:

    pc <- c(1, -2.2, -13.4, -5.1, 1.9, 0.52)
    
    2 回复  |  直到 6 年前
        1
  •  5
  •   Zheyuan Li    6 年前

    实际上,鞍点可以通过 polyroot

    SaddlePoly <- function (pc) {
      ## a polynomial needs be at least quadratic to have saddle points
      if (length(pc) < 3L) {
        message("A polynomial needs be at least quadratic to have saddle points!")
        return(numeric(0))
        }
      ## polynomial coefficient of the 1st derivative
      pc1 <- pc[-1] * seq_len(length(pc) - 1)
      ## roots in complex domain
      croots <- polyroot(pc1)
      ## retain roots in real domain
      ## be careful when testing 0 for floating point numbers
      rroots <- Re(croots)[abs(Im(croots)) < 1e-14]
      ## note that `polyroot` returns multiple root with multiplicies
      ## return unique real roots (in ascending order)
      sort(unique(rroots))
      }
    
    xs <- SaddlePoly(pc)
    #[1] -3.77435640 -1.20748286 -0.08654384  2.14530617
    

    计算多项式

    我们需要能够计算一个多项式来绘制它。 My this answer g PolyVal .

    PolyVal <- function (x, pc, nderiv = 0L) {
      ## check missing aruments
      if (missing(x) || missing(pc)) stop ("arguments missing with no default!")
      ## polynomial order p
      p <- length(pc) - 1L
      ## number of derivatives
      n <- nderiv
      ## earlier return?
      if (n > p) return(rep.int(0, length(x)))
      ## polynomial basis from degree 0 to degree `(p - n)`
      X <- outer(x, 0:(p - n), FUN = "^")
      ## initial coefficients
      ## the additional `+ 1L` is because R vector starts from index 1 not 0
      beta <- pc[n:p + 1L]
      ## factorial multiplier
      beta <- beta * factorial(n:p) / factorial(0:(p - n))
      ## matrix vector multiplication
      base::c(X %*% beta)
      }
    

    例如,我们可以计算多项式的所有鞍点:

    PolyVal(xs, pc)
    #[1]  79.912753  -4.197986   1.093443 -51.871351
    

    用双色方案为单调片段绘制一个多项式

    ViewPoly <- function (pc, extend = 0.1) {
      ## get saddle points
      xs <- SaddlePoly(pc)
      ## number of saddle points (if 0 the whole polynomial is monotonic)
      n_saddles <- length(xs)
      if (n_saddles == 0L) {
        message("the polynomial is monotonic; program exits!")
        return(NULL)
        }
      ## set a reasonable xlim to include all saddle points
      if (n_saddles == 1L) xlim <- c(xs - 1, xs + 1)
      else xlim <- extendrange(xs, range(xs), extend)
      x <- c(xlim[1], xs, xlim[2])
      ## number of monotonic pieces
      k <- length(xs) + 1L 
      ## monotonicity (positive for ascending and negative for descending)
      y <- PolyVal(x, pc)
      mono <- diff(y)
      ylim <- range(y)
      ## colour setting (red for ascending and green for descending)
      colour <- rep.int(3, k)
      colour[mono > 0] <- 2
      ## loop through pieces and plot the polynomial
      plot(x, y, type = "n", xlim = xlim, ylim = ylim)
      i <- 1L
      while (i <= k) {
        ## an evaluation grid between x[i] and x[i + 1]
        xg <- seq.int(x[i], x[i + 1L], length.out = 20)
        yg <- PolyVal(xg, pc)
        lines(xg, yg, col = colour[i])
        i <- i + 1L
        }
      ## add saddle points
      points(xs, y[2:k], pch = 19)
      ## return (x, y)
      list(x = x, y = y)
      }
    

    我们可以通过以下方式将问题中的示例多项式形象化:

    ViewPoly(pc)
    #$x
    #[1] -4.07033952 -3.77435640 -1.20748286 -0.08654384  2.14530617  2.44128930
    #
    #$y
    #[1]  72.424185  79.912753  -4.197986   1.093443 -51.871351 -45.856876
    

        2
  •  1
  •   Zheyuan Li    6 年前

    SaddlePoly PolyVal 带R包 polynom .

    library(polynom)
    

    SaddlePoly <- function (pc) {
      ## a polynomial needs be at least quadratic to have saddle points
      if (length(pc) < 3L) {
        message("A polynomial needs be at least quadratic to have saddle points!")
        return(numeric(0))
        }
      ## polynomial coefficient of the 1st derivative
      ## pc1 <- pc[-1] * seq_len(length(pc) - 1)  ## <- removed
      ## roots in complex domain
      croots <- solve(deriv(polynomial(pc)))      ## <- use package "polynom"
      ## retain roots in real domain
      ## be careful when testing 0 for floating point numbers
      rroots <- Re(croots)[abs(Im(croots)) < 1e-14]
      ## note that `polyroot` returns multiple root with multiplicies
      ## return unique real roots (in ascending order)
      sort(unique(rroots))
      }
    
    xs <- SaddlePoly(pc)
    #[1] -3.77435640 -1.20748286 -0.08654384  2.14530617
    

    ## a complete re-implementation using package "polynom"
    PolyVal <- function (x, pc, nderiv = 0L) {
      ## check missing aruments
      if (missing(x) || missing(pc)) stop ("arguments missing with no default!")
      ## create "polynomial" object
      p <- polynomial(pc)
      ## take derivatives
      i <- 0
      while (i < nderiv) {
        p <- deriv(p)
        i <- i + 1
        }
      ## evaluate "polynomial" with "predict"
      predict(p, x)
      }
    
    PolyVal(xs, pc)
    #[1]  79.912753  -4.197986   1.093443 -51.871351
    

    ## use `ViewPoly` as it is
    ViewPoly(pc)
    #$x
    #[1] -4.07033952 -3.77435640 -1.20748286 -0.08654384  2.14530617  2.44128930
    #
    #$y
    #[1]  72.424185  79.912753  -4.197986   1.093443 -51.871351 -45.856876
    


    多项式 poly.calc 函数允许从根或拉格朗日插值构造多项式。

    ## (x - 1) ^ 3
    p1 <- poly.calc(rep(1, 3))
    
    ## x * (x - 1) * (x - 2) * (x - 3)
    p2 <- poly.calc(0:3)
    
    ## Lagrange interpolation through 0:4 and rnorm(5, 0:4, 1)
    set.seed(0); x <- 0:4; y <- rnorm(5, 0:4, 1)
    p3 <- poly.calc(x, y)
    

    要查看这些多项式,我们可以使用函数 plot.polynomial PolyView . 然而,这两个函数在选择上有不同的逻辑 xlim 为了这个阴谋。

    par(mfrow = c(3, 2), mar = c(4, 4, 1, 1))
    ## plot `p1`
    plot(p1)
    ViewPoly(unclass(p1))
    ## plot `p2`
    plot(p2)
    ViewPoly(unclass(p2))
    ## plot `p3`
    plot(p3)
    ViewPoly(unclass(p3))