(module deriv-lang-test "deriv-lang.ss"
(require (planet "test.ss" ("schematics" "schemeunit.plt" 2))
(planet "text-ui.ss" ("schematics" "schemeunit.plt" 2)))
(provide deriv-lang-test-suite)
(define-simple-check (check-close? eps a b)
(< (abs (- a b)) eps))
(define deriv-lang-test-suite
(test-suite
"deriv-lang.ss test suite"
(test-case
"testing add, negate, sub, mul, invert, negate, and partial"
(let ((f (lambda (x y)
(+ (* 3 (- x))
(* (/ y) x)
(* x x x)
(/ y x y)
(- 3 (* x y))))))
(check-equal? (f 2 3) 1/6)
(check-equal? (((partial 0) f) 2 3) 73/12)
(check-equal? (((partial 1) f) 2 3) -20/9)))
(test-case
"testing =, <, >, <=, >=, and sin and cos"
(let ((f (lambda (x) (if (= x 3) (cos x) (sin x)))))
(check-equal? ((D f) 3) (- (sin 3)))
(check-equal? ((D f) 4) (cos 4)))
(let ((f (lambda (x) (if (< x 3) (cos x) (sin x)))))
(check-equal? ((D f) 2.9) (- (sin 2.9)))
(check-equal? ((D f) 4) (cos 4)))
(let ((f (lambda (x) (if (> x 3) (cos x) (sin x)))))
(check-equal? ((D f) 4) (- (sin 4)))
(check-equal? ((D f) 3) (cos 3)))
(let ((f (lambda (x) (if (<= x 3) (cos x) (sin x)))))
(check-equal? ((D f) 3) (- (sin 3)))
(check-equal? ((D f) 4) (cos 4)))
(let ((f (lambda (x) (if (>= x 3) (cos x) (sin x)))))
(check-equal? ((D f) 3) (- (sin 3)))
(check-equal? ((D f) 2) (cos 2))))
(test-case
"testing exp and log"
(let ((f (lambda (x) (exp (log x)))))
(check-close? 1e-8 ((D f) (random)) 1.0)))
(test-case
"testing trig and inverse trig"
(let ((x (random)))
(check-close? 1e-8 ((D sin) x) (/ ((D asin) (sin x))))
(check-close? 1e-8 ((D cos) x) (/ ((D acos) (cos x))))
(check-close? 1e-8 ((D tan) x) (/ ((D atan) (tan x)))))
(let ((my-atan2 (lambda (y x) (atan (/ y x))))
(x (random))
(y (random)))
(check-close? 1e-8 (((partial 0) atan) y x) (((partial 0) my-atan2) y x))
(check-close? 1e-8 (((partial 1) atan) y x) (((partial 1) my-atan2) y x))))
(test-case
"testing sqrt and exp"
(let ((x (random)))
(check-close? 1e-8 ((D sqrt) x) ((D (lambda (x) (exp (/ (log x) 2)))) x))))
(test-case
"testing expt"
(let* ((my-expt (lambda (a b) (exp (* b (log a)))))
(x (random))
(y (random)))
(check-close? 1e-8 (((partial 0) expt) x y) (((partial 0) my-expt) x y))
(check-close? 1e-8 (((partial 1) expt) x y) (((partial 1) my-expt) x y))))
(test-case
"up to three derivatives of exp"
(let ((x (random)))
(check-close? 1e-8 (exp x) ((D exp) x))
(check-close? 1e-8 (exp x) ((D (D exp)) x))
(check-close? 1e-8 (exp x) ((D (D (D exp))) x))))
(test-case
"random (fixed) polynomial has correct derivatives (up to D^3)."
(let ((f (lambda (x) (- -10
(* 62 (expt x 5))
(* -97 (expt x 4))
(* 73 (expt x 3))
(* 4 (* x x))
(* 83 x))))
(Df (lambda (x) (+ (* -310 (expt x 4))
(* 388 (expt x 3))
(* -219 (expt x 2))
(* -8 x)
-83)))
(DDf (lambda (x) (+ (* -1240 (expt x 3))
(* 1164 (* x x))
(* -438 x)
-8)))
(DDDf (lambda (x) (+ (* -3720 (* x x))
(* 2328 x)
-438)))
(x (random)))
(check-close? 1e-8 (Df x) ((D f) x))
(check-close? 1e-8 (DDf x) ((D (D f)) x))
(check-close? 1e-8 (DDDf x) ((D (D (D f))) x))))
(test-case
"Higher-order derivative test (from Barak A. Pearlmutter)"
(check-close? 1e-8
((D (lambda (x) ((D (lambda (y) (+ x y))) 1))) 1)
0)))))