いmemoize再帰的機能Lisp?
-
05-07-2019 - |
質問
私はLisp初心者です。監督-選手コメンmemoize、再帰関数計算の数 Collatz配列 (例題14 プロジェクトオイラー).私のコードとしては:
(defun collatz-steps (n)
(if (= 1 n) 0
(if (evenp n)
(1+ (collatz-steps (/ n 2)))
(1+ (collatz-steps (1+ (* 3 n)))))))
(defun p14 ()
(defvar m-collatz-steps (memoize #'collatz-steps))
(let
((maxsteps (funcall m-collatz-steps 2))
(n 2)
(steps))
(loop for i from 1 to 1000000
do
(setq steps (funcall m-collatz-steps i))
(cond
((> steps maxsteps)
(setq maxsteps steps)
(setq n i))
(t ())))
n))
(defun memoize (fn)
(let ((cache (make-hash-table :test #'equal)))
#'(lambda (&rest args)
(multiple-value-bind
(result exists)
(gethash args cache)
(if exists
result
(setf (gethash args cache)
(apply fn args)))))))
のmemoize機能と同様に、指定されたもの にLisp ます。
このコードはなんとして高速に比べて非memoizedバージョン。と思いますの再帰呼び出しで呼び出しのmemoized数のある種の敗戦です。その場合は、何が正しい方向でのmemoization。れる方法はありましてすべての通話の機能を呼び出memoized版自体が不要で、特m-collatz階シンボル?
編集:を修正したコードを
(defvar m-collatz-steps (memoize #'collatz-steps))
では何をしています。編集前の私は誤り:
(defvar collatz-steps (memoize #'collatz-steps))
見るとエラーにしてくれた別のフィラデルフィを使ってみましたこの最後のdefvar自体を変更する再帰呼び出しに
(1+ (funcall collatz-steps (/ n 2)))
(1+ (funcall collatz-steps (1+ (* 3 n))))
これはそうに行うのmemoization(高速から約60秒間15秒)が必要になりますの変更に独自の機能です。りクリーナーソリューションになる、機能しているのでしょうか。
解決
思いを共Lispで、別の名前空間のための変数や関数名です。するためmemoizeの機能名シンボルを変更する必要があり、その機能結合を通じて、アクセス用メソッド`fdefinition':
(setf (fdefinition 'collatz-steps) (memoize #'collatz-steps))
(defun p14 ()
(let ((mx 0) (my 0))
(loop for x from 1 to 1000000
for y = (collatz-steps x)
when (< my y) do (setf my y mx x))
mx))
他のヒント
のようなこと:
(setf collatz-steps (memoize lambda (n)
(if (= 1 n) 0
(if (evenp n)
(1+ (collatz-steps (/ n 2)))
(1+ (collatz-steps (1+ (* 3 n))))))))
IOW:オリジナル(非memoized)関数は匿名のみファイル名をつけたいときの結果memoizingます。
こちらはmemoize機能rebindsのシンボル機能:
(defun memoize-function (function-name)
(setf (symbol-function function-name)
(let ((cache (make-hash-table :test #'equal)))
#'(lambda (&rest args)
(multiple-value-bind
(result exists)
(gethash args cache)
(if exists
result
(setf (gethash args cache)
(apply fn args)))))))
おいしいて思ったこと。
(defun collatz-steps (n)
(if (= 1 n) 0
(if (evenp n)
(1+ (collatz-steps (/ n 2)))
(1+ (collatz-steps (1+ (* 3 n)))))))
(memoize-function 'collatz-steps)
だができるunmemoizeです。
を変更する"オリジナルの"機能が必要なので、あなたの言葉を借りれはありませんの再帰呼出し(s)が更新されるmemoizedバージョン。
幸いなことに、lispの作品ではの機能 名前 各時間が必要で呼び出されます。これで十分に置き換え機能との結合にmemoized版の機能、その再帰呼び出しまで自動的に検索および再突入のmemoization.
huaiyuanのコードをキーステップ:
(setf (fdefinition 'collatz-steps) (memoize #'collatz-steps))
このトリックもPerlです。言語のようにし、memoizedバージョンの機能コードす。
一部のlispの実装を提供するシステム"の助言を提供する、標準化された構造のための交換機能を強化したバージョンです。のほか、機能アップのようなmemoization、このに役立つ高性能なデバッグを挿入しデバッグ版画(または完全に止まるとcontinuable迅速な変更は元のコードです。
ご注意いくつかの:
(defun foo (bar)
... (foo 3) ...)
である、上記の機能を呼び出します。
共通のLispファイルをコンパイラではFOOは変わりません。いませ------------更新したFOOます。変更した場合の機能結合FOO、その通話の機能ますが、古い機能です。
でmemoizing自己再帰の機能は使用できませんの。特にないご利用の場合良いコンパイラです。
きであり、常に行くのシンボルの例:(funcall'foo3)
(DEFVAR...)をトップレベル。で使用しない内で機能する。の場合を宣言した変数で設定SETQはSETFます。
お問いうハッシュテーブルの中間ます。
この機能は同一ピーター Norvigを事例として機能するように思えるので良い候補者memoizationができます。
図3(機能を'Hailstone')を独自に論文memoization("自動Memoizationとしてのソフトウェアエンジニアリングツールの実世界のAIシステム").
さんの顔をもに取得する場合の力学memoization、なん化とスピードアップを図っている。
前に書いた少しmemoizationルーチンのスキームを用いた連鎖の閉鎖のmemoized状態:
(define (memoize op)
(letrec ((get (lambda (key) (list #f)))
(set (lambda (key item)
(let ((old-get get))
(set! get (lambda (new-key)
(if (equal? key new-key) (cons #t item)
(old-get new-key))))))))
(lambda args
(let ((ans (get args)))
(if (car ans) (cdr ans)
(let ((new-ans (apply op args)))
(set args new-ans)
new-ans))))))
このニーズを使用するように:
(define fib (memoize (lambda (x)
(if (< x 2) x
(+ (fib (- x 1)) (fib (- x 2)))))))
っていると確信していき移植にお好きな語彙的に小scoped Lisp風味。
思うように:
(let ((memo (make-hash-table :test #'equal)))
(defun collatz-steps (n)
(or (gethash n memo)
(setf (gethash n memo)
(cond ((= n 1) 0)
((oddp n) (1+ (collatz-steps (+ 1 n n n))))
(t (1+ (collatz-steps (/ n 2)))))))))
でも機能的なものではないものを手でいます。レストランも得られないときには、いくつかのハンディunmemoizedのバージョンを試験および清算キャッシュが隣接する"非常に難しい".