[SML 7878] Re: 連想計算というリフレクティブな手法

Narita Takaoki Narita.Takaoki @ exc.epson.co.jp
2010年 12月 15日 (水) 17:04:04 JST


成田です。

> sumim です。
> 
> まだ流れを追いきれていないので、Smalltalk的に書き直せていませんが、
> とりあえず成田さんのCLのコードをSmalltalkで動くよう直訳してみました。

おお、すばらしい・・・
ストレートに移すと、やっぱりブロックだらけになりますよね。

> ...流れ

じっくり見れば分かるでしょうから、解説もいらないとは思いますが、考え方の
解説をおこがましくも一応してみます。

大枠は、特定の条件を満たした繰り返し作用に対する「逐次平方」の適用で
す。フィボナッチ数列への適用は、フィボナッチと逐次平方でググると出てくる
かな?

;; SICP もキーワードにすると良いかも?

逐次平方を簡単にみるなら、フィボナッチ数列の場合では、二行行列でフィボ
ナッチ数列の第1項(= 1)、第0項(= 0)を要素とするものを f_1 として、二行二
列の行列 T を考え、その要素を

    t_1_1 := 1      t_1_2 := 1
    t_2_1 := 1      t_2_2 := 0

とします。そうするとフィボナッチ数列の定義は、

 f_n := T * f_n-1, n > 1

で与えられるので、

 f_n := (T^n) * f_1

に持ち込め、T^n の計算ができればよろしくなります。

冪の形になっているので、

 T^n = if  n is even then (T^{n/2})^2 else (T^{n-1}) * T.

を用いて、n が 1 になるまで分解して計算すると、T^n が求まり、計算量は
O(log(n)) になります。これをストレートに Common Lisp で書くと、

(defun sequential-square (f n x)
  (cond ((= n 1) x)
        ((evenp n) (let ((fn (sequential-square f (/ n 2) x))) (funcall f fn fn)))
        (t (funcall f x (sequential-square f (1- n) x)))))

(defun fibonacci (n)
  (car (sequential-square  ;; car は、f_1 と掛けて、f_n を取り出すのと一緒。
         (lambda (x y)  ;; このラムダ式は行列の掛け算もどきです。
           (let ((a (car x)) (b (cadr x)) (c (caddr x)) (d (cadddr x))
                 (m (car y)) (n (cadr y)) (l (caddr y)) (o (cadddr y)))
             (list (+ (* a m) (* b l)) (+ (* a n) (* b o)) (+ (* c m) (* d l))
                   (+ (* c n) (* d o)))))
         (1- n)
         '(1 1 1 0)))) ;; (t_1_1  t_1_2  t_2_1  t_2_2) で代用して2行2列行列を表現。

こんなところでしょうか。ここまでが、逐次平方の骨子です。

ちなみに、T * (T * T) も (T * T) * T も同じであるのですが、これが逐次平方を適用
するための「特定の条件」かな?

先に示した大げさな一般化を施した版は、行列の代わりにもうすこし一般性のある
線形関数による合成関数を想起して、合成関数演算を composition-op としてみ
たものです。composition-op は丁度 T に対する * の一般化でしょうか。fibo は、
T そのものにあたることになります。

となるとですね・・・sequentialSquare や compositionOp をメソッド化するとすると
Block クラスでしょうか・・・はてさて?

まあ、鷲見さんの書かれてたものに比べ、数学的発想(?)で対処しているので
Smalltalk の仕掛けで面白く・・という方向じゃないですねぇ・・・

;;; プログラミング発想だとメモ化とかストリーム化とかになるのでしょう・・・

> Squeak4.1とVisualWorks7.7で動作します。
> 
> 
> | sequentialSquare compositionOp fibo fibonacci |
> 
> sequentialSquare := nil.
> sequentialSquare := [:compOp :operator :n |
>    n < 1 ifTrue: [nil] ifFalse: [
>    n = 1 ifTrue: [operator] ifFalse: [
>    n > 1
>       ifTrue: [
>          n odd ifTrue: [
>             compOp
>                value: (sequentialSquare
>                   value: compOp value: operator value: n - 1)
>                value: operator]
>       ifFalse: [
>          | sqOp |
>          sqOp := sequentialSquare
>             value: compOp value: operator value: n / 2.
>          compOp value: sqOp value: sqOp]]]]].
> 
> compositionOp := [:func1 :func2 |
>    [:x | func1 value: (func2 value: x)]].
> 
> fibo := [:x | Array with: x first + (x at: 2) with: x first].
> 
> fibonacci := [:x |
>    x < 1 ifTrue: [nil] ifFalse: [
>    x = 1
>       ifTrue: [1]
>       ifFalse: [
>          ((sequentialSquare
>                value: compositionOp value: fibo value: x - 1)
>             value: #(1 0)) first]]].
> 
> fibonacci value: 1000
> 
> 
> 2010年12月14日17:11 Narita Takaoki <Narita.Takaoki @ exc.epson.co.jp>:
> > 成田です。
> >
> >> sumim こと鷲見です。
> >>
> >> 連想計算でもリフレクティブでもないので恐縮ですが、
> >> にぎやかしにと、2つほど考えてみました。
> >
> > 同様にぎやかしですが、それどころか Smalltalk にもなってません。
> >
> > これを Smalltalk 的に書くとしたら?で詰まってしまった・・・
> > Common Lisp で書いてしまいましたが:
> >
> > (defun sequential-square (comp-op operator n)
> >  (assert (integerp n) (n)) ;; 本質には関係しないので無視してください。
> >  (cond ((< n 1) nil)
> >        ((= n 1) operator)
> >        ((> n 1)
> >         (cond ((oddp n)
> >                (funcall comp-op
> >                 (sequential-square comp-op operator (1- n)) 
> operator))
> >               ('t
> >                (let
> >                 ((sq-op (sequential-square comp-op operator 
> (/ n 2))))
> >                 (funcall comp-op sq-op sq-op)))))))
> >
> > (defun composition-op (func1 func2)
> >  (lambda (x) (funcall func1 (funcall func2 x))))
> >
> > (defun fibo (x) (list (+ (car x) (cadr x)) (car x)))
> >
> > (defun fibonacci (x)
> >  (cond ((< x 1) nil)
> >        ((= x 1) 1) ;; かなりインチキ
> >        ('t
> >         (car
> >          (funcall
> >           (sequential-square #'composition-op #'fibo (1- x)) '(1 
> > 0))))))
> 


SML メーリングリストの案内