hermite.scm 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  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. ;;;; Hermite interpolation 6/1/89 (mh)
  21. ;;; Edited by GJS 10Jan09
  22. (declare (usual-integrations))
  23. ;;; This is currently configured to work for polynomials with only
  24. ;;; numerical coefficients. (gjs)
  25. ;;; Return the cubic polynomial that matches specified value and
  26. ;;; slope at each of two points.
  27. (define make-cubic-interpolant
  28. ;; create the basic Hermite interpolants
  29. (let ((h0 (poly:dense-> '(1 0 -3 2))) ;h(0)=1, h(1)=h'(0)=h'(1)=0
  30. (h1 (poly:dense-> '(0 0 3 -2))) ;h(1)=1, h(0)=h'(0)=h'(1)=0
  31. (h2 (poly:dense-> '(0 1 -2 1))) ;h'(0)=1, h(0)=h(1)=h'(1)=0
  32. (h3 (poly:dense-> '(0 0 -1 1))));h'(1)=1, h(0)=h(1)=h'(0)=0
  33. (define (cubic-interpolant a fa fpa b fb fpb)
  34. ;; make the polynomial on [0,1] and then scale.
  35. ;; Note: the derivative must be scaled initially
  36. (let ((s (- b a)))
  37. (let ((p (poly:+ (poly:+ (poly:scale h0 fa)
  38. (poly:scale h1 fb))
  39. (poly:+ (poly:scale h2 (* s fpa))
  40. (poly:scale h3 (* s fpb))))))
  41. (poly:arg-shift (poly:arg-scale p (list (/ 1 s)))
  42. (list (- a))))))
  43. cubic-interpolant))
  44. ;;; As above, but return a 5th-degree polynomial that matches value
  45. ;;; and first two derivatives at each of two points.
  46. (define make-quintic-interpolant
  47. (let ((m
  48. (m:invert (matrix-by-rows '(1 0 0 0 0 0)
  49. '(0 1 0 0 0 0)
  50. '(0 0 2 0 0 0)
  51. '(1 1 1 1 1 1)
  52. '(0 1 2 3 4 5)
  53. '(0 0 2 6 12 20)))))
  54. (define (quintic-interpolant a fa fpa fppa b fb fpb fppb)
  55. (let* ((s (- b a))
  56. (v (vector fa (* fpa s) (* fppa s s)
  57. fb (* fpb s) (* fppb s s)))
  58. (p (poly:dense-> (vector->list (matrix*vector m v)))))
  59. (poly:arg-shift (poly:arg-scale p (list (/ 1 s)))
  60. (list (- a)))))
  61. quintic-interpolant))
  62. ;;; Given an order of contact n, return a procedure that generates
  63. ;;; an Hermite interpolating polynomial of degree 2n+1, which matches
  64. ;;; function value along with first n derivatives at two selected
  65. ;;; points. The returned procedure expects two arguments, each a list
  66. ;;; of length n+2:
  67. ;;; (a f(a) f'(a) f"(a) ... ), (b f(b) f'(b) f"(b) ... )
  68. (define (make-hermite-interpolator n)
  69. (let* ((m (fix:+ n 1))
  70. (2m (fix:* 2 m))
  71. (! (lambda (n k) ;k*(k+1)*(k+2)*...*(k+n-1)
  72. (let loop ((i 0) (prod 1))
  73. (if (fix:= i n)
  74. prod
  75. (loop (fix:+ i 1)
  76. (fix:* prod (fix:+ k i)))))))
  77. (term (lambda (i j)
  78. (if (fix:< i m)
  79. (if (fix:= j i) (! i 1) 0)
  80. (let ((i (fix:- i m)))
  81. (if (fix:< j i)
  82. 0
  83. (! i (fix:- j (fix:+ i -1))))))))
  84. (mat (m:invert (m:generate 2m 2m term))))
  85. (define (hermite-interpolator avals bvals)
  86. (let* ((a (car avals)) (b (car bvals))
  87. (s (- b a))
  88. (*s (lambda (x) (* s x)))
  89. (scale (letrec
  90. ((scale
  91. (lambda (L)
  92. (if (null? L)
  93. '()
  94. (cons (car L)
  95. (scale (map *s (cdr L))))))))
  96. scale))
  97. (v (list->vector (append (scale (cdr avals)) (scale (cdr bvals)))))
  98. (p (poly:dense-> (vector->list (matrix*vector mat v)))))
  99. (poly:arg-shift (poly:arg-scale p (list (/ 1 s)))
  100. (list (- a)))))
  101. hermite-interpolator))