缓存Matlab函数结果到文件

yoa*_*ram 3 simulation matlab caching bitstring

我在Matlab写一个模拟.我最终将运行这个模拟数百次.在每次模拟运行中,都有数百万个模拟周期.在每个循环中,我计算一个非常复杂的函数,需要~0.5秒才能完成.函数输入是一个长位数组(> 1000位) - 这是一个0和的数组1.我认为该位阵列中的一个矩阵01,并为他们中的每一个我仅运行该函数一旦-正如我保存的结果在不同的阵列(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
Run Code Online (Sandbox Code Playgroud)

我有两个问题,真的:

  1. 有没有更有效的方法来找到矩阵中的行的索引然后'ismember'?

  2. 由于我多次运行模拟,并且我得到的位数有很大的重叠,我想在运行之间缓存矩阵,这样我就不会在相同的位数组上重复计算函数再次.我怎么做?

Pur*_*uit 5

这两个问题的答案都是使用地图.有几个步骤可以做到这一点.

  1. 首先,您需要一个函数将bit_array转换为数字或字符串.例如,[0 1 1 0 1 0]变成'011010'.(Matlab仅支持标量或字符串键,这就是为什么需要此步骤.)

  2. 定义了一个地图对象

    cachedRunMap = containers.Map;  %See edit below for more on this
    
    Run Code Online (Sandbox Code Playgroud)
  3. 要检查特定案例是否已运行,请使用iskey.

    cachedRunMap.isKey('011010');
    
    Run Code Online (Sandbox Code Playgroud)
  4. 要添加运行结果,请使用附加语法

    cachedRunMap('011010') = [0 1 1 0 1];  %Or whatever your result is.  
    
    Run Code Online (Sandbox Code Playgroud)
  5. 要检索缓存结果,请使用获取语法

    tmpResult = cachedRunMap.values({'011010'});
    
    Run Code Online (Sandbox Code Playgroud)

这应该有效地存储和检索值,直到您用完系统内存.


把它们放在一起,现在你的代码看起来像这样:

%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
Run Code Online (Sandbox Code Playgroud)

如果你想要一个不是字符串的键,那么需要在步骤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');
Run Code Online (Sandbox Code Playgroud)

设置KeyType'char'将地图设置为使用字符串作为键.所有其他类型必须是标量.


关于问题的扩展(根据您最近的评论)

  • 在会话之间保存数据:将此映射保存到*.mat文件应该没有问题,直到系统内存的限制

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

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

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