{{ message }}

Instantly share code, notes, and snippets.

# ericnormand/00 symbolic differentiation pt2.md

Last active Aug 30, 2019

symbolic differentiation, pt 2

Now that we've got a basic symbolic differentiator (and the numeric one), we could simplify the expressions. SICP gives some basic simplifications.

1. `(+ 0 x) => x` or additive identity
2. `(* 1 x) => x` or multiplicative identity
3. `(+ 1 2) => 3` or constant simplification
4. `(* 3 2) => 6` or constant simplification

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

The challenge this week is to integrate these easy simplifications into the differentiator. If you didn't do last week's challenge, grab someone else's code and work from that.

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 =number? "" [expr num] (and (number? expr) (= expr num))) (defn make-sum [expr1 expr2] (cond (=number? expr1 0) expr2 (=number? expr2 0) expr1 (and (number? expr1) (number? expr2)) (+ expr1 expr2) :else (list '+ expr1 expr2))) (defn make-product [expr1 expr2] (cond (or (=number? expr1 0) (=number? expr2 0)) 0 (=number? expr1 1) expr2 (=number? expr2 1) expr1 (and (number? expr1) (number? expr2)) (* expr1 expr2) :else (list '* expr1 expr2))) (defn deriv "symbolic differentiation. issue: 339 question: https://gist.github.com/ericnormand/397337f77faa6b68815c29f60f532db0" [expr v] (cond (list? expr) (let [[op a b] expr] (case op + (make-sum (deriv a v) (deriv b v)) * (make-sum (make-product a (deriv b v)) (make-product b (deriv a v))) (throw (ex-info "unrecognized error" {:op op})))) (= expr v) 1 (or (number? expr) (symbol? expr)) 0 :else (throw (ex-info "unrecognized expr" {:expr expr})))) (comment (deriv '(+ x 5) 'x) (deriv '(+ (* 7 x) (* x 5)) 'x) (deriv '(+ (* 12 x) (* x 5)) 'x) )
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 (:require [clojure.walk :as w])) (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})))) (defmulti simplify-op #(and (list? %) (= 3 (count %)) (first %))) (defmethod simplify-op '+ [[_ a b :as expr]] (cond (and (number? a) (number? b)) (+ a b) (= 0 a) b (= 0 b) a :else expr)) (defmethod simplify-op '* [[_ a b :as expr]] (cond (and (number? a) (number? b)) (* a b) (or (= 0 a) (= 0 b)) 0 (= 1 a) b (= 1 b) a :else expr)) (defmethod simplify-op :default [expr] expr) (def simplify (partial w/postwalk simplify-op))
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] (cond (= 0 u) v (= 0 v) u (and (number? u) (number? v)) (+ u v) :else (list '+ u v))) (defn prod? [expr] (and (seq? expr) (= '* (first expr)))) (defn ->prod [u v] (cond (= 0 u) 0 (= 0 v) 0 (= 1 u) v (= 1 v) u (and (number? u) (number? v)) (* u v) :else (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)))))) (comment (deriv '(+ (* x x) x 5) 'x) )