{ "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 }