Main Content

memoize

メモ化のセマンティクスを関数ハンドルに追加

説明

"メモ化" は、プログラムを高速化するために使用される最適化手法で、時間のかかる関数呼び出しの結果をキャッシュし、同じ入力でプログラムが呼び出されたときにキャッシュした結果を返します。

次のすべての条件が満たされている場合、関数呼び出しのメモ化を検討してください。

  • パフォーマンスが重要である。

  • 関数の処理に時間がかかる。

  • 関数の戻り値が入力値のみにより決定され、関数の副作用がない。

  • システム メモリが一意の入力と出力の組み合わせを格納するのに十分である。

memoizedFcn = memoize(fh) はメモ化のセマンティクスを入力関数ハンドルに追加し、MemoizedFunction オブジェクトを返します。fh の呼び出しと同様に memoizedFcn を呼び出します。ただし、memoizedFcn は関数ハンドルではありません。

MemoizedFunction オブジェクトは入力のキャッシュと、対応する出力を保持します。このオブジェクトを呼び出すと、MATLAB® は次の条件が満たされている場合に、関連付けられたキャッシュ済みの出力値を返します。

  1. 入力引数がキャッシュ済みの入力と数値的に等しくなっている。入力値を比較する場合、MATLAB は NaN を等価として扱います。

  2. 要求された出力引数の数が、入力に関連付けられたキャッシュ済みの出力の数と一致している。

関数のメモ化は、MemoizedFunction オブジェクトではなく、入力関数と関連付けられます。そのため、次のことに注意してください。

  • 新しい MemoizedFunction オブジェクトを同じ関数に作成すると、同じデータへの別の参照が作成されます。同じ関数をメモ化する 2 つの変数は、キャッシュおよびオブジェクト プロパティ値 (キャッシュ サイズなど) を共有します。次の例では、変数 ab はキャッシュを共有し、キャッシュ サイズが同じ値です。

    a = memoize(@svd);
    b = memoize(@svd);
    同様に、b のキャッシュ (b.clearCache) をクリアすると、a のキャッシュと、関数 svd をメモ化する他のすべての変数もクリアされます。clearCacheMemoizedFunction のオブジェクト関数です。

  • MemoizedFunction オブジェクトを新しい変数に割り当てると、同じデータへの別の参照が作成されます。次の例では、変数 cd はデータを共有しています。

    c = memoize(@svd);
    d = c;

  • 変数をクリアしても、その入力関数に関連付けられたキャッシュはクリアされません。ワークスペースに存在しなくなった MemoizedFunction オブジェクトのキャッシュをクリアするには、同じ関数に新しい MemoizedFunction オブジェクトを作成して、その新しいオブジェクトに関数 clearCache を使用します。あるいは、関数 clearAllMemoizedCaches を使用して、すべての MemoizedFunction オブジェクトのキャッシュをクリアできます。

注意

MemoizedFunction オブジェクトは、基となる関数の更新を認識しません。メモ化された関数に関連付けられた関数を変更する場合、オブジェクト関数 clearCache でキャッシュをクリアします。

すべて折りたたむ

同じ入力を複数回演算する可能性がある場合に特異値分解の実行速度を向上させるには、関数 svd をメモ化します。

fh = @svd;
memoizedFcn = memoize(fh);

行列を作成して、特異値分解の結果をキャッシュします。関数呼び出しの実行速度を測定します。

X = magic(1234);
tic
[U,S,V]= memoizedFcn(X);
preCachedTime = toc
preCachedTime = 0.4655

同じ入力を使用して、メモ化された関数をもう一度呼び出します。キャッシュされた結果の使用による速度向上を確認するには、関数呼び出しの実行速度をもう一度測定します。

tic
[U,S,V]= memoizedFcn(X);
postCachedTime = toc
postCachedTime = 0.0038

現在の作業フォルダーで、ファイル computeNumberCombinations.m を作成します。このファイルには、n 個の項目から一度に k 個を取り出す組み合わせの数を計算するための次の関数があります。

type computeNumberCombinations.m
function c = computeNumberCombinations(n,k)
% Calculate number of combinations of n items taken k at a time
c = fact(n)/(fact(n-k)*fact(k));
end

function f = fact(n)
f = 1;
for m = 2:n
    f = f*m;   
end
end

ワークスペース内にあるすべての MemoizedFunction オブジェクトのキャッシュをクリアします。

clearAllMemoizedCaches

関数 computeNumberCombinations をメモ化して、繰り返される入力値の計算速度を向上させます。

fh = @computeNumberCombinations;
memoizedFcn = memoize(fh);

メモ化された関数を呼び出して、関数呼び出しの実行速度を測定します。この関数呼び出しは、指定した入力に対する結果をキャッシュします。

tic
c = memoizedFcn(42e5,137);
preCachedTime = toc
preCachedTime = 0.0212

メモ化された関数を呼び出して、関数呼び出しの実行速度をもう一度測定します。この関数呼び出しはキャッシュされた結果を使用し、関数は実行しません。

tic
c = memoizedFcn(42e5,137);
postCachedTime = toc
postCachedTime = 0.0035

入力引数

すべて折りたたむ

メモ化する関数。関数ハンドルとして指定します。

例: memoizedEigs = memoize(@eigs)

データ型: function_handle

ヒント

  • 同じ関数ハンドルで memoize を複数回呼び出すと、同じ MemoizedFunction オブジェクトが返されます。以下に例を示します。

    x = memoize(@plus);
    y = memoize(@plus);
    x == y
    ans =
    
      logical
    
       1
  • 何らかのグローバル状態を設定したり、I/O 操作を実行するなどの副作用がある関数はメモ化しないでください。メモ化された関数を同じ入力で呼び出しても、以降の呼び出しでは副作用は繰り返されません。たとえば、関数 randi をメモ化する場合、メモ化された関数を同じ入力引数で呼び出すと必ず同じ値を返します。

    fh = @randi;
    memoized_fh = memoize(fh);
    
    fh_result = [fh(100) fh(100) fh(100)]
    memoized_result = [memoized_fh(100) memoized_fh(100) memoized_fh(100)]
    fh_result =
    
        18    71     4
    
    
    memoized_result =
    
        28    28    28

バージョン履歴

R2017a で導入

参考

関数

オブジェクト