{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# CS 201: Derivatives\n", "
\n",
""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"See https://courses.cs.washington.edu/courses/cse341/15wi/racket/deriv.rkt\n",
"\n",
"A classic example of Scheme/Racket programs as data: symbolic differentiation. Adapted from \n",
" \"Structure and Interpretation of Computer Programs\" Chapter 2. Somewhat modified: doesn't use\n",
"constructor functions, and it separates out finding the derivative from simplifying expressions. \n",
"\n",
"Includes unit tests.\n",
"\n",
"The top-level function deriv takes an expression and a variable, \n",
"and returns the derivative of that expression with respect to the variable,\n",
"in simplified form"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {},
"outputs": [],
"source": [
"(require racket)\n",
"(require racket/base)"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"(define (deriv exp var)\n",
" (simplify (basic-deriv exp var)))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"basic-deriv
takes the derivative of an expression exp with respect to a variable and returns the result without simplification"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"(define (basic-deriv exp var)\n",
" (cond ((number? exp) 0)\n",
" ((symbol? exp)\n",
" (if (eq? exp var) 1 0))\n",
" ((sum? exp)\n",
" (list '+ (basic-deriv (left exp) var) (basic-deriv (right exp) var)))\n",
" ((product? exp)\n",
" (list '+\n",
" (list '* (left exp) (basic-deriv (right exp) var))\n",
" (list '* (basic-deriv (left exp) var) (right exp))))\n",
" (else (error \"unknown expression type -- basic-deriv\" exp))))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Predicates and access functions\n",
"\n",
"Test whether a list structure is a sum"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"(define (sum? x)\n",
" (and (pair? x) (eq? (car x) '+)))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Test whether a list structure is a product."
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"(define (product? x)\n",
" (and (pair? x) (eq? (car x) '*)))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Get the left hand part of a sum or product"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"(define (left exp)\n",
" (cadr exp))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Get the right hand part of a sum or product"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"(define (right exp)\n",
" (caddr exp))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Basic simplification function (nothing too fancy ... doesn't know about commutativity or associativity)\n"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"(define (simplify exp)\n",
" (cond ((sum? exp) (simplify-sum exp))\n",
" ((product? exp) (simplify-product exp))\n",
" ;; if we get here, we can't simplify exp\n",
" (else exp)))"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [],
"source": [
"(define (simplify-sum exp)\n",
" ;; to simplify a sum, we need to first recursively simplify the left and right parts\n",
" (let ((a (simplify (left exp)))\n",
" (b (simplify (right exp))))\n",
" (cond ((equal? 0 a) b)\n",
" ((equal? 0 b) a)\n",
" ((and (number? a) (number? b)) (+ a b))\n",
" (else (list '+ a b)))))"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"(define (simplify-product exp) \n",
" (let ((a (simplify (left exp)))\n",
" (b (simplify (right exp))))\n",
" (cond ((or (equal? 0 a) (equal? 0 b)) 0)\n",
" ((equal? 1 a) b)\n",
" ((equal? 1 b) a)\n",
" ((and (number? a) (number? b)) (* a b))\n",
" (else (list '* a b)))))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Unit tests\n",
"\n",
"See http://docs.racket-lang.org/rackunit/quick-start.html\n",
"for documentation on Racket's unit testing library."
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
"(require rackunit)"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [],
"source": [
"(define deriv-tests \n",
" (test-suite \n",
" \"tests for deriv program\"\n",
" (check-equal? (deriv 'x 'x) 1 \"deriv of x wrt x\")\n",
" (check-equal? (deriv 'y 'x) 0 \"deriv of y wrt x\")\n",
" (check-equal? (deriv '(+ x 3) 'x) 1 \"deriv of (+ x 3) wrt x\")\n",
" (check-equal? (deriv '(* (+ 2 3) x) 'x) 5 \"deriv of unsimplified expression\")\n",
" (check-equal? (deriv '(+ x y) 'x) 1 \"deriv of (+ x y) wrt x\")\n",
" ;; simplification is not as clever as it could be in the following case:\n",
" (check-equal? (deriv '(* (+ x 1) (+ x -1)) 'x) '(+ (+ x 1) (+ x -1)) \"deriv of (* (+ x 1) (+ x -1)) wrt x\")\n",
" (check-equal? (deriv '(* (* x y) (+ x 3)) 'x) '(+ (* x y) (* y (+ x 3))) \"complex deriv\")\n",
" ))"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"7 success(es) 0 failure(s) 0 error(s) 7 test(s) run\n"
]
},
{
"data": {
"text/html": [
"0
"
],
"text/plain": [
"0"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(require rackunit/text-ui)\n",
";; this line runs the tests ....\n",
"(run-tests deriv-tests)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"$$ \\frac{\\mathrm{d}}{\\mathrm{d}x}x = 0 $$|"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"1
"
],
"text/plain": [
"1"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(deriv 'x 'x)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"$$ \\frac{\\mathrm{d}}{\\mathrm{d}x}y = 1 $$"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"0
"
],
"text/plain": [
"0"
]
},
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(deriv 'y 'x)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"$$ \\frac{\\mathrm{d}}{\\mathrm{d}x} (x + 3) = 1 $$"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"1
"
],
"text/plain": [
"1"
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(deriv '(+ x 3) 'x)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"$$ \\frac{\\mathrm{d}}{\\mathrm{d}x} (x * (2 + 3)) = 5 $$"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"5
"
],
"text/plain": [
"5"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(deriv '(* x (+ 2 3)) 'x)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"$$ \\frac{\\mathrm{d}}{\\mathrm{d}x} (x + y) = 1 $$"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"1
"
],
"text/plain": [
"1"
]
},
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(deriv '(+ x y) 'x)"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"'(+ 1 0)
"
],
"text/plain": [
"'(+ 1 0)"
]
},
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(basic-deriv '(+ x y) 'x)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"$$ \\frac{\\mathrm{d}}{\\mathrm{d}x} (x + 1)(x + 3) = (x + 1)(x - 1) $$"
]
},
{
"cell_type": "code",
"execution_count": 31,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"'(+ x x)
"
],
"text/plain": [
"'(+ x x)"
]
},
"execution_count": 31,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(deriv '(* (+ x 1) (+ x -1)) 'x)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"$$ \\frac{\\mathrm{d}}{\\mathrm{d}x} (xy)(x + 3) = (xy(y(x + 3)) $$"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"'(+ (* x y) (* y (+ x 3)))
"
],
"text/plain": [
"'(+ (* x y) (* y (+ x 3)))"
]
},
"execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(deriv '(* (* x y) (+ x 3)) 'x) "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## More Robust Derivatives\n",
"\n",
"See calculus.rkt\"> and fundamental.rkt"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {},
"outputs": [],
"source": [
"(require \"calculus.rkt\")"
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"'(+ (* x y) (* y (+ x 3)))
"
],
"text/plain": [
"'(+ (* x y) (* y (+ x 3)))"
]
},
"execution_count": 27,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(deriv '(* (* x y) (+ x 3)) 'x) "
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"'(cos x)
"
],
"text/plain": [
"'(cos x)"
]
},
"execution_count": 28,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(deriv '(sin x) 'x)"
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"'(+ (* 6 x x) (* 6 x x) (* 6 x x))
"
],
"text/plain": [
"'(+ (* 6 x x) (* 6 x x) (* 6 x x))"
]
},
"execution_count": 29,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(deriv '(* x 2 x x 3) 'x)"
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"'(+ (* 10 (** x 4)) (* 12 (** x 2)))
"
],
"text/plain": [
"'(+ (* 10 (** x 4)) (* 12 (** x 2)))"
]
},
"execution_count": 30,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(deriv '(+ (* 2 (** x 5)) (* 4 (** x 3))) 'x)"
]
},
{
"cell_type": "code",
"execution_count": 34,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"'(+ x x)
"
],
"text/plain": [
"'(+ x x)"
]
},
"execution_count": 34,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(deriv '(* (+ x 1) (+ x -1)) 'x)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Racket",
"language": "racket",
"name": "racket"
},
"language_info": {
"codemirror_mode": "scheme",
"file_extension": ".rkt",
"mimetype": "text/x-racket",
"name": "Racket",
"pygments_lexer": "racket",
"version": "7.4"
}
},
"nbformat": 4,
"nbformat_minor": 4
}