#lang scheme/base
(require "math.ss"
(lib "contract.ss"))
(define-struct chebyshev-series
(coefficients
order
(lower #:mutable)
(upper #:mutable)))
(provide
(rename-out (make-chebyshev-series-order unchecked-make-chebyshev-series-order)
(chebyshev-series-init unchecked-chebyshev-series-init)
(chebyshev-eval unchecked-chebyshev-eval)
(chebyshev-eval-n unchecked-chebyshev-eval-n)))
(provide/contract
(struct chebyshev-series ((coefficients (vectorof real?))
(order natural-number/c)
(lower real?)
(upper real?)))
(make-chebyshev-series-order
(-> natural-number/c chebyshev-series?))
(chebyshev-series-init
(-> chebyshev-series? procedure? real? real? void?))
(chebyshev-eval
(-> chebyshev-series? real? real?))
(chebyshev-eval-n
(-> chebyshev-series? natural-number/c real? real?)))
(define (make-chebyshev-series-order order)
(make-chebyshev-series
(make-vector (+ order 1))
order
0.0 0.0))
(define (chebyshev-series-init cs func a b)
(when (>= a b)
(error 'chebyshev-series-init
"null function interval [a,b]"))
(set-chebyshev-series-lower! cs a)
(set-chebyshev-series-upper! cs b)
(let* ((order (chebyshev-series-order cs))
(coefficients (chebyshev-series-coefficients cs))
(bma (* 0.5 (- b a)))
(bpa (* 0.5 (+ b a)))
(fac (/ 2.0 (+ order 1.0)))
(f (make-vector (+ order 1))))
(do ((k 0 (+ k 1)))
((> k order) (void))
(let ((y (cos (* pi (/ (+ k 0.5) (+ order 1))))))
(vector-set! f k
(func (+ (* y bma) bpa)))))
(do ((j 0 (+ j 1)))
((> j order) (void))
(let ((sum 0.0))
(do ((k 0 (+ k 1)))
((> k order) (void))
(set! sum (+ sum (* (vector-ref f k)
(cos (/ (* pi j (+ k 0.5))
(+ order 1)))))))
(vector-set! coefficients j (* fac sum))))))
(define (chebyshev-eval cs x)
(let* ((coefs (chebyshev-series-coefficients cs))
(order (chebyshev-series-order cs))
(lower (chebyshev-series-lower cs))
(upper (chebyshev-series-upper cs))
(d 0.0)
(dd 0.0)
(y (/ (- (* 2.0 x) lower upper) (- upper lower)))
(y2 (* 2.0 y)))
(do ((j order (- j 1)))
((= j 0) (void))
(let ((temp d))
(set! d (+ (* y2 d) (- dd) (vector-ref coefs j)))
(set! dd temp)))
(+ (* y d) (- dd) (* 0.5 (vector-ref coefs 0)))))
(define (chebyshev-eval-n cs n x)
(let* ((coefs (chebyshev-series-coefficients cs))
(order (chebyshev-series-order cs))
(lower (chebyshev-series-lower cs))
(upper (chebyshev-series-upper cs))
(d 0.0)
(dd 0.0)
(y (/ (- (* 2.0 x) lower upper) (- upper lower)))
(y2 (* 2.0 y)))
(do ((j (min n order) (- j 1)))
((= j 0) (void))
(let ((temp d))
(set! d (+ (* y2 d) (- dd) (vector-ref coefs j)))
(set! dd temp)))
(+ (* y d) (- dd) (* 0.5 (vector-ref coefs 0)))))