Instantly share code, notes, and snippets.

# ericnormand/00 symbolic differentiation.md

Last active August 23, 2019 15:52
Show Gist options
• Save ericnormand/397337f77faa6b68815c29f60f532db0 to your computer and use it in GitHub Desktop.

symbolic differentiation

I got excited last week by the numeric differentiator challenge. When I originally read that section of SICP so many years ago, I was elated. Do you know how hard that would be to do in Java?

Now for something that's even harder to do in Java: symbolic differentiation.

Here's the relevant link into SICP, for reference.

The challenge this week is to use four differentiation formulas to make a symbolic differentiator. It has been a while since I've done any calculus, so I had to look these up:

1. `dc/dx = 0` (for a constant c, or variable c different from x)
2. `dx/dx = 1`
3. `d(u+v)/dx = du/dx + dv/dx` (addition rule)
4. `d(uv)/dx = u(dv/dx) + v(du/dx)` (product rule)

This won't differentiate every formula, but it will differentiate sums and products of variables and numbers. You should make a function that takes an expression and a variable to differentiate by, like so:

`(deriv '(+ x 5) 'x) ;=> (+ 1 0)`

Don't worry about simplifying the final expression. Just make sure it's right.

This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
 (ns symderiv.main) (defn deriv [expr v] (cond (list? expr) (let [[op a b] expr] (case op + (list '+ (deriv a v) (deriv b v)) * (list '+ (list '* a (deriv b v)) (list '* b (deriv a v))) (throw (ex-info "Unrecognized operator" {:op op})))) (= expr v) 1 (or (number? expr) (symbol? expr)) 0 :else (throw (ex-info "Unrecognized expression" {:expr expr})))) (ns symderiv.main (:require [meander.strategy.delta :as r])) (defn deriv [expr var] (let [operations (r/rewrite ; addition (+ ?u ?v) (+ ~(deriv ?u var) ~(deriv ?v var)) ; multiplication (* ?u ?v) (+ (* ?u ~(deriv ?v var)) (* ?v ~(deriv ?u var)))) var' (r/pipe (r/pred #(= var %)) (r/build 1)) constant' (r/pipe (r/pred number?) (r/build 0)) other-var' (r/pipe (r/pred symbol?) (r/build 0)) choice (r/choice operations var' other-var' constant')] (choice expr)))
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
 (defn variable? [v] (symbol? v)) (defn same-variable? [v1 v2] (and (variable? v1) (variable? v2) (= v1 v2))) (defn sum? [expr] (and (seq? expr) (= '+ (first expr)))) (defn ->sum [u v] (list '+ u v)) (defn prod? [expr] (and (seq? expr) (= '* (first expr)))) (defn ->prod [u v] (list '* u v)) (defn deriv [expr var] (cond (same-variable? expr var) 1 (or (variable? expr) (number? expr)) 0 (sum? expr) (let [[_ u v] expr] (->sum (deriv u var) (deriv v var))) (prod? expr) (let [[_ u v] expr] (->sum (->prod u (deriv v var)) (->prod v (deriv u var))))))
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
 (defn sum? [exp] (= (first exp) '+)) (defn product? [exp] (= (first exp) '*)) (defn pred* [exp clauses] (when clauses (list 'if (list (first clauses) exp) (second clauses) (pred* exp (-> clauses next next))))) (defmacro pred [exp & clauses] (pred* exp clauses)) (defn deriv [exp v] (pred exp number? 0 symbol? (if (= exp v) 1 0) sum? (list '+ (deriv (second exp) v) (deriv (last exp) v)) product? (list '+ (list '* (second exp) (deriv (last exp) v)) (list '* (deriv (second exp) v) (last exp)))))