polyinterp.scm 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. #| -*-Scheme-*-
  2. Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
  3. 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
  4. 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Massachusetts
  5. Institute of Technology
  6. This file is part of MIT/GNU Scheme.
  7. MIT/GNU Scheme is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2 of the License, or (at
  10. your option) any later version.
  11. MIT/GNU Scheme is distributed in the hope that it will be useful, but
  12. WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. General Public License for more details.
  15. You should have received a copy of the GNU General Public License
  16. along with MIT/GNU Scheme; if not, write to the Free Software
  17. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301,
  18. USA.
  19. |#
  20. ;;;; Numerical construction of Polynomial interpolations
  21. ;;; Edited by GJS 10Jan09
  22. (declare (usual-integrations))
  23. ;;; Alter the coefficients of polynomial P so that its domain [a,b] is
  24. ;;; mapped onto the canonical domain [-1,1].
  25. (define (poly-domain->canonical p a b)
  26. (if (<= b a)
  27. (error "bad interval: must have a < b in POLY-DOMAIN->CANONICAL"))
  28. (let ((c (/ (+ a b) 2)) (d (/ (- b a) 2)))
  29. ;; p(x) [a,b] --> p(y+c) = q(y) [-d,d] --> q(d*z) = r(z) [-1,1]
  30. (poly:arg-scale (poly:arg-shift p (list c)) (list d))))
  31. ;;; Alter the coefficients of polynomial P so that its domain [-1,1]
  32. ;;; is mapped onto [a,b]. This is the inverse operation to
  33. ;;; POLY-DOMAIN->CANONICAL.
  34. (define (poly-domain->general p a b)
  35. (if (<= b a)
  36. (error "bad interval: must have a < b in POLY-DOMAIN->GENERAL"))
  37. (let ((c (/ (+ a b) 2)) (d (/ (- b a) 2)))
  38. (poly:arg-shift (poly:arg-scale p (list (/ 1 d))) (list (- c)))))
  39. ;;; Given a list of distinct abscissas xs = (x1 x2 ... xn) and a list
  40. ;;; of ordinates ys = (y1 y2 ... yn), return the Lagrange interpolation
  41. ;;; polynomial through the points (x1, y1), (x2, y2), ... (xn, yn).
  42. (define (make-interp-poly ys xs)
  43. ;; given a point list, return a poly that evaluates to 1 at the
  44. ;; first point and 0 at the others.
  45. (define (roots->poly roots)
  46. (a-reduce poly:*
  47. (map (lambda (r) (poly:- poly:identity r))
  48. roots)))
  49. (define (unity-at-first-point point-list)
  50. (let* ((x (car point-list))
  51. (px (apply * (map (lambda (u) (- x u))
  52. (cdr point-list)))))
  53. (if (zero? px)
  54. (error "MAKE-INTERP-POLY: abscissas not distinct"))
  55. (poly:scale (roots->poly (cdr point-list)) (/ 1 px))))
  56. (let loop ((p poly:zero) (points xs) (values ys))
  57. (if (null? values)
  58. p
  59. (let ((q (unity-at-first-point points)))
  60. (loop (poly:+ p (poly:scale q (car values)))
  61. (left-circular-shift points)
  62. (cdr values))))))
  63. ;;; Given a function F, an interval [a, b], and a specified N > 0: we
  64. ;;; generate a polynomial P of order N (and degree N-1) that interpolates
  65. ;;; F at the "Chebyshev" points mapped onto [a, b]. We assume that the
  66. ;;; absolute error function E(x) = |F(x) - P(x)| is unimodal between
  67. ;;; adjacent interpolation points. Thus E(x) has altogether N+1 "bumps";
  68. ;;; the largest of these has height Bmax and the smallest has height Bmin.
  69. ;;; Of course Bmax is an error bound for the approximation of F by P on
  70. ;;; [a, b]; but Bmin has heuristic significance as a lower-bound for the
  71. ;;; reduced error that might be obtained by tuning the interpolation points
  72. ;;; to meet the equiripple criterion. We return the list (P Bmax Bmin).
  73. (define (get-poly-and-errors f a b n)
  74. (let* ((c (/ (+ a b) 2))
  75. (d (/ (- b a) 2))
  76. (imap (lambda (x) (+ c (* d x)))) ;map [-1, 1] -> [a, b]
  77. (points (map imap (cheb-root-list n)))
  78. (p (make-interp-poly (map f points) points))
  79. (abserr (lambda (x) (abs (- (f x) (poly:value p x)))))
  80. (abserr-a (abserr a))
  81. (abserr-b (abserr b))
  82. (max-and-min-bumps
  83. (let loop ((pts points)
  84. (bmax (max abserr-a abserr-b))
  85. (bmin (min abserr-a abserr-b)))
  86. (if (< (length pts) 2)
  87. (list bmax bmin)
  88. (let ((x0 (car pts)) (x1 (cadr pts)))
  89. (let ((bump (cadr (brent-max abserr x0 x1 1e-6))))
  90. (cond ((> bump bmax) (loop (cdr pts) bump bmin))
  91. ((< bump bmin) (loop (cdr pts) bmax bump))
  92. (else (loop (cdr pts) bmax bmin)))))))))
  93. (list p (car max-and-min-bumps) (cadr max-and-min-bumps))))
  94. ;;; Often we want a function that computes the value of a polynomial
  95. ;;; at given points.
  96. (define* ((polynomial-function poly) x)
  97. (assert (pcf? poly) "Not a polynomial")
  98. (poly/horner-univariate poly x))