3

私はMatlabでシミュレーションを書いています。最終的には、このシミュレーションを何百回も実行します。各シミュレーション実行には、数百万回のシミュレーション サイクルがあります。これらの各サイクルで、非常に複雑な関数を計算しますが、~0.5完了するまでに数秒かかります。関数入力は長いビット配列 (>1000 ビット) です。これは と の配列0です10ビット配列をとの行列に保持し、1それぞれに対して関数を 1 回だけ実行します。結果を別の配列 (res) に保存し、関数を実行する前にビット配列が行列に含まれているかどうかを確認します。 :

for i=1:1000000000
    %pick a bit array somehow
    [~,indx] = ismember(bit_array,bit_matrix,'rows');
    if indx == 0
        indx = length(results) + 1;
        bit_matrix(indx,:) = bit_array;
        res(indx) = complex_function(bit_array);
    end
    result = res(indx)
    %do something with result
end

本当に2つの質問があります:

  1. 「ismember」よりも行列内の行のインデックスを見つける効率的な方法はありますか?

  2. シミュレーションを何度も実行し、取得しているビット配列に大きなオーバーラップがあるため、実行間で行列をキャッシュして、同じビット配列に対して関数を何度も再計算しないようにします。また。それ、どうやったら出来るの?

4

3 に答える 3

5

両方の質問に対する答えは、マップを使用することです。これを行うには、いくつかの手順があります。

  1. まず、bit_array を数値または文字列に変換する関数が必要です。たとえば、 に変わり[0 1 1 0 1 0]ます'011010'。(Matlab はスカラー キーまたは文字列キーのみをサポートしているため、この手順が必要です。)

  2. マップ オブジェクトの定義

    cachedRunMap = containers.Map;  %See edit below for more on this
    
  3. 特定のケースが実行されたかどうかを確認するには、 を使用しますiskey

    cachedRunMap.isKey('011010');
    
  4. 実行の結果を追加するには、追加構文を使用します

    cachedRunMap('011010') = [0 1 1 0 1];  %Or whatever your result is.  
    
  5. キャッシュされた結果を取得するには、取得構文を使用します

    tmpResult = cachedRunMap.values({'011010'});
    

これにより、システム メモリが不足するまで、値を効率的に保存および取得できます。


これをまとめると、コードは次のようになります。

%Hacky magic function to convert an array into a string of '0' and '1'
strFromBits = @(x) char((x(:)'~=0)+48); %'

%Initialize the map
cachedRunMap = containers.Map;

%Loop, computing and storing results as needed
for i=1:1000000000
    %pick a bit array somehow
    strKey = strFromBits(bit_array);
    if cachedRunMap.isKey(strKey)
        result = cachedRunMap(strKey);
    else
        result = complex_function(bit_array);
        cachedRunMap(strKey) = reult;
    end
    %do something with result
end

文字列ではないキーが必要な場合は、ステップ 2 で宣言する必要があります。いくつかの例を次に示します。

cachedRunMap = containers.Map('KeyType', 'char', 'ValueType', 'any');
cachedRunMap = containers.Map('KeyType', 'double', 'ValueType', 'any');
cachedRunMap = containers.Map('KeyType', 'uint64', 'ValueType', 'any');
cachedRunMap = containers.Map('KeyType', 'uint64', 'ValueType', 'double');

aKeyTypeを設定すると'char'、文字列をキーとして使用するようにマップが設定されます。他のすべての型はスカラーでなければなりません。


これをスケールアップする際の問題について(最近のコメントによる)

  • セッション間のデータの保存: システム メモリの制限まで、このマップを *.mat ファイルに保存しても問題はありません。

  • 古いデータの消去: このマップに LRU 機能を追加する簡単な方法を知りません。Java 実装を見つけることができれば、Matlab 内で非常に簡単に使用できます。そうしないと、キーが最後に使用された時間を追跡する最も効率的な方法を決定するのに、ある程度の考慮が必要になります。

  • 同時セッション間でのデータ共有: ご指摘のとおり、これにはおそらくデータベースが効率的に実行される必要があります。DB テーブルは 2 つの列 (LRU 機能を実装する場合は 3 つ)、キー、値 (および必要に応じて最後に使用された時間) になります。「結果」が SQL に簡単に適合しないタイプ (たとえば、不均一なサイズの配列や複雑な構造) の場合は、それを格納する方法をさらに検討する必要があります。また、データベースにアクセスする方法も必要です (たとえば、データベース ツールボックス、または Mathworks ファイル交換のさまざまなツール)。最後に、実際にサーバー上にデータベースをセットアップする必要があります (たとえば、私のように安価な場合は MySql、または最も経験が豊富な場合、または最もヘルプを見つけることができる場合)。これは実際にはそれほど難しいことではありませんが、最初は少し時間と労力がかかります。

    考慮すべきもう 1 つのアプローチ (効率ははるかに劣りますが、データベースは必要ありません) は、データ ストアを多数 (たとえば、数千または数百万) のマップに分割することです。それぞれを個別の *.mat ファイルに保存し、そのマップに含まれるキー (文字列キーの最初の N 文字など) に基づいたファイル名を付けてから、必要に応じてセッション間でこれらのファイルをロード/保存します。これはかなり遅くなります...使用状況によっては、毎回ソース関数から再計算する方が速い場合があります...しかし、DBをセットアップせずに考えることができる最良の方法です(明らかにより良い答えです)。

于 2012-02-14T23:04:20.847 に答える
0
  1. 大きなリストの場合、並べ替えられた順序で維持するのにそれほどコストがかからない場合は、手動でコード化されたバイナリ検索が ismember よりも優れている可能性があります。それが本当にあなたのボトルネックなら。プロファイラーを使用して、ismember が実際にどれだけのコストをかけているかを確認してください。個別の値が多すぎない場合は、bit_matrix をchar配列にパックし、それをキーとして使用することで、それらを container.Map に格納することもできます。

  2. メモリに収まるほど小さい場合は、 と を使用して MAT ファイルに格納できsaveますload。基本的な Matlab データ型を格納できます。シミュレーションを実行の最後にsave蓄積resし、次に呼び出されたときにbit_matrix再実行します。load

于 2012-02-14T23:01:10.773 に答える
0

containers.Map()高速化目的で使うといいと思います。

一般的な考え方は、すべてのハッシュ値を含むマップを保持することです。ビット配列がハッシュ関数の下で一様に分布している場合、ほとんどの場合、 への呼び出しは必要ありませんismember

key typeはMatlabでは配列にできないため、ビット配列でハッシュ関数を計算できます。

例えば:

 function s = GetHash(bitArray)
      s = mod( sum(bitArray), intmax('uint32'));          
 end

これはお粗末なハッシュ関数ですが、原理を理解するには十分です。コードは次のようになります。

map = containers.Map('KeyType','uint32','ValueType','any');
for i=1:1000000000
    %pick a bit array somehow
    s = GetHash(bit_array);   
    if isKey  %Do the slow check.
        [~,indx] = ismember(bit_array,bit_matrix,'rows');
    else
       map(s) = 1;
       continue;
    end
    if indx == 0
        indx = length(results) + 1;
        bit_matrix(indx,:) = bit_array;
        res(indx) = complex_function(bit_array);
    end
    result = res(indx)
    %do something with result
end
于 2012-02-14T23:02:11.377 に答える