# 2.3.2 Example: Symbolic Differentiation を Python でやってみた 〜表示は Scheme 風味で〜

SICP2.3.2 Example: Symbolic Differentiation の The differentiation program with abstract data あたりを Python でやってみた

##### scheme
```;2.3.2  Example: Symbolic Differentiation
;The differentiation program with abstract data

(define (deriv exp var)
(cond ((number? exp) 0)
((variable? exp)
(if (same-variable? exp var) 1 0))
((sum? exp)
(deriv (augend exp) var)))
((product? exp)
(make-sum
(make-product (multiplier exp)
(deriv (multiplicand exp) var))
(make-product (deriv (multiplier exp) var)
(multiplicand exp))))
(else
(error "unknown expression type -- DERIV" exp))))

;Representing algebraic expressions

(define (variable? x) (symbol? x))
(define (same-variable? v1 v2)
(and (variable? v1) (variable? v2) (eq? v1 v2)))
(define (make-sum a1 a2) (list '+ a1 a2))
(define (make-product m1 m2) (list '* m1 m2))
(define (sum? x)
(and (pair? x) (eq? (car x) '+)))
(define (product? x)
(and (pair? x) (eq? (car x) '*)))

(deriv '(+ x 3) 'x)
;(+ 1 0)
(deriv '(* x y) 'x)
;(+ (* x 0) (* 1 y))
(deriv '(* (* x y) (+ x 3)) 'x)
;(+ (* (* x y) (+ 1 0)) (* (+ (* x 0) (* 1 y)) (+ x 3)))
```
##### python
```#2.3.2  Example: Symbolic Differentiation
#The differentiation program with abstract data

def deriv(exp, var):
if isinstance(exp, int):
return 0
if variable_q(exp):
if same_variable_q(exp, var):
return 1
return 0
if sum_q(exp):
if product_q(exp):
return make_sum(make_product(multiplier(exp),
deriv(multiplicand(exp), var)),
make_product(deriv(multiplier(exp), var),
multiplicand(exp)))
else:
print "unknown expression type -- DERIV %s" % exp

def variable_q(x):
return isinstance(x, str or int)
def same_variable_q(v1, v2):
return variable_q(v1) and variable_q(v2) and v1 == v2
def make_sum(a1, a2):
return ['+', a1, a2]
def make_product(m1, m2):
return ['*', m1, m2]
def sum_q(x):
return isinstance(x, list) and x[0] == '+'
return s[1]
def augend(s):
return s[2]
def product_q(x):
return isinstance(x, list) and x[0] == '*'
def multiplier(p):
return p[1]
def multiplicand(p):
return p[2]

print deriv(['+', 'x', 3], 'x')
#['+', 1, 0]
print deriv(['*', 'x', 'y'], 'x')
#['+', ['*', 'x', 0], ['*', 1, 'y']]
print deriv(['*', ['*', 'x', 'y'], ['+', 'x', 3]], 'x')
#['+', ['*', ['*', 'x', 'y'], ['+', 1, 0]], ['*', ['+', ['*', 'x', 0], ['*', 1, 'y']], ['+', 'x', 3]]]
```

なんかおかしいかも。symboleあたりこの認識でいいのかしらん(´･ω･`)？

##### 結果が見づらいから Scheme 風に表示してみた
```def like_a_scheme_str(deriv):
s_deriv = str(deriv)
r_str = [["[","("],["]",")"],[",",""],["'",""]]
for s in r_str:
s_deriv = s_deriv.replace(s[0], s[1])
return s_deriv
print like_a_scheme_str(deriv(['+', 'x', 3], 'x'))
print like_a_scheme_str(deriv(['*', 'x', 'y'], 'x'))
print like_a_scheme_str(deriv(['*', ['*', 'x', 'y'], ['+', 'x', 3]], 'x'))
```

``` (+ 1 0)
(+ (* x 0) (* 1 y))
(+ (* (* x y) (+ 1 0)) (* (+ (* x 0) (* 1 y)) (+ x 3)))
```

ＯＫ牧場(ﾟДﾟ)b

##### scheme
```(define (make-sum a1 a2)
(cond ((=number? a1 0) a2)
((=number? a2 0) a1)
((and (number? a1) (number? a2)) (+ a1 a2))
(else (list '+ a1 a2))))

(define (=number? exp num)
(and (number? exp) (= exp num)))

(define (make-product m1 m2)
(cond ((or (=number? m1 0) (=number? m2 0)) 0)
((=number? m1 1) m2)
((=number? m2 1) m1)
((and (number? m1) (number? m2)) (* m1 m2))
(else (list '* m1 m2))))

(deriv '(+ x 3) 'x)
;1
(deriv '(* x y) 'x)
;y
(deriv '(* (* x y) (+ x 3)) 'x)
;(+ (* x y) (* y (+ x 3)))
```
##### python
```def make_sum(a1, a2):
if equal_number_q(a1, 0):
return a2
if equal_number_q(a2, 0):
return a1
if isinstance(a1, int) and isinstance(a2, int):
return a1 + a2
else:
return ['+', a1, a2]

def equal_number_q(exp, num):
return isinstance(exp, int) and exp == num

def make_product(m1, m2):
if equal_number_q(m1, 0) or equal_number_q(m2, 0):
return 0
if equal_number_q(m1, 1):
return m2
if equal_number_q(m2, 1):
return m1
if isinstance(m1, int) and isinstance(m2, int):
return m1 * m2
else:
return ['*', m1, m2]

print like_a_scheme_str(deriv(['+', 'x', 3], 'x'))
print like_a_scheme_str(deriv(['*', 'x', 'y'], 'x'))
print like_a_scheme_str(deriv(['*', ['*', 'x', 'y'], ['+', 'x', 3]], 'x'))
#1
#y
#(+ (* x y) (* y (+ x 3)))
```