2012-02-14 88 views
3

我在Matlab中编写了一个模拟。 我最终将运行这个模拟数百次。 在每次模拟运行中,都有数百万次模拟周期。 在每个这些循环中,我计算了一个非常复杂的函数,这需要~0.5秒完成。 函数输入是一个长位数组(> 1000位) - 这是一个01的数组。 我举几个01矩阵的位阵列,并且对于它们中的每一个我只运行一次函数 - 因为我将结果保存在不同的数组(res)中,并检查位数组是否在矩阵之前运行功能:将Matlab函数结果缓存到文件

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 

我有两个quesitons,真正做到:

  1. 有没有找到一个行的索引矩阵则“ismember”更有效的方法?

  2. 由于我多次运行模拟,并且在得到的位数组中存在很大的重叠,我想在运行之间缓存矩阵,以便不重新计算同一位上的函数一遍又一遍。我怎么做?

+0

你如何在内存中存储bit_array和bit_matrix?作为“逻辑”?或者打包到其他数据类型? (每个“逻辑”值实际上存储在一个字节中,而不是一位,即使它只能取两个可能的值。) – 2012-02-14 22:51:30

+0

并且关于bit_array总共有多少不同的值?是否足够重叠,以至于可能将所有这些数据及其结果存储在内存中?或者将他们中的一些需要卸载到磁盘?单个仿真中的仿真周期是否存在重叠,或只是跨越不同的仿真?在模拟中bit_arrays的完成顺序是否存在局部性(例如,通常只有一些低阶位发生了变化)? – 2012-02-14 22:59:37

+0

我没有声明任何东西,所以我想我正在使用普通的int32? – yoavram 2012-02-15 07:45:32

回答

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'); 

设置一个'char'KeyType将地图设置为使用字符串作为科YS。所有其他类型都必须是标量。


关于你这规模达(根据您最近的评论)问题会话之间

  • 保存数据:应该没有问题,保存此映射到* .MAT文件,到系统内存限制

  • 清除旧数据:我不知道将LRU功能添加到此映射的直接方法。如果你能找到一个Java实现,你可以很容易地在Matlab中使用它。否则,需要考虑一些问题以确定最后一次使用密钥的最有效方法。

  • 在并发会话之间共享数据:如您所述,这可能需要数据库有效执行。数据库表格将是两列(如果您想实现LRU功能,则为3列),键值,(如果需要,最后使用时间)。如果你的“结果”不是一个容易适合SQL的类型(例如一个不规则大小的数组或者复杂的结构),那么你将需要考虑如何存储它。您还需要一种访问数据库的方法(例如数据库工具箱或Mathworks文件交换中的各种工具)。最后,你需要在服务器上设置一个数据库(例如MySql,如果你像我一样便宜,或者你有最多的经验,或者可以找到最多的帮助。)这实际上并不难,但它第一次需要花费一点时间和精力。

    另一种考虑的方法(效率低得多,但不需要数据库)可能会将数据存储分解成大量(例如1000或数百万)地图。使用基于该映射中包含的键的文件名(例如,字符串键的前N个字符)将每个文件保存到单独的* .mat文件中,然后根据需要在会话之间加载/保存这些文件。这将非常缓慢......根据您的使用情况,每次从源函数重新计算可能会更快......但这是我可以在不设置数据库的情况下想到的最好方式(显然是更好的答案)。

+0

好的!唯一的问题是,将bit_array转换为字符串是否不会太慢,从而导致一切效率低下。 – 2012-02-14 23:08:05

+0

谢谢,回到你身边。当他提到单次运行0.5秒时,我认为字符串转换时间可能不会受到速率限制因素的影响。 – Pursuit 2012-02-14 23:14:50

+0

好的,但我确实有很多不同的值,所以我必须使用[LRU](http://en.wikipedia.org/wiki/Cache_algorithms#Least_Recently_Used)地图,对吧? 此外,因为我希望缓存在多个并行模拟运行中保持不变,所以我需要它在文件或数据库上,不是吗? – yoavram 2012-02-15 07:44:57

0
  1. 对于一个大名单,一个手工编码的二进制搜索可以击败ismember,如果将其保持在有序是不是太昂贵。如果那真是你的瓶颈。使用分析器查看ismember真正花费你多少钱。如果没有太多不同的值,您也可以将它们存储在一个containers.Map中,方法是将bit_matrix放入一个char数组中,并将其用作关键字。

  2. 如果它足够小以适应内存,则可以使用saveload将它存储在MAT文件中。他们可以存储任何基本的Matlab数据类型。在其运行结束时模拟save积累的resbit_matrix,并在下次调用它们时重新录入load

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