読者です 読者をやめる 読者になる 読者になる

牌語備忘録 -pygo

あくまでもメモです。なるべくオフィシャルの情報を参照してください。

牌語備忘録 -pygo

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

SICP Python

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)
         (make-sum (deriv (addend exp) var)
                   (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 (addend s) (cadr s))
(define (augend s) (caddr s))
(define (product? x)
  (and (pair? x) (eq? (car x) '*)))
(define (multiplier p) (cadr p))
(define (multiplicand p) (caddr p))


(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):
        return make_sum(deriv(addend(exp), var), deriv(augend(exp), var))
    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] == '+'
def addend(s):
    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)))

OK牧場(゚Д゚)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)))