matlab中重复执行,重复数组元素的副本:在MATLAB中运行长度解码

问题陈述

我们有一系列值, vals和runlens , runlens :

vals = [1,3,2,5] runlens = [2,2,1,3]

我们需要在runlens每个对应元素的vals次重复每个元素。 因此,最终的输出是:

output = [1,1,3,3,2,5,5,5]

前瞻性的方法

MATLAB中速度最快的工具之一是cumsum ,在处理不规则模式的矢量化问题时非常有用。 在陈述的问题中, runlens的不同元素会带来不规则性。

现在,为了利用cumsum ,我们需要在这里做两件事:初始化一个zeros数组,并将“合适的”值放置在零数组上的“关键”位置,使得在应用“ cumsum ”之后, runlens时间的重复vals的最后阵列。

步骤:让我们对上述步骤进行编号,使预期的方法更容易:

1)初始化零数组:长度是多少? 由于我们重复runlens时间,零数组的长度必须是所有runlens的总和。

2)查找关键位置/索引:现在这些关键位置是沿着零点阵列的位置,其中来自vals每个元素开始重复。 因此,对于runlens = [2,2,1,3] ,映射到零数组上的关键位置将是:

[X 0 X 0 XX 0 0], where X's are those key positions.

3)找到合适的价值:在使用cumsum之前最后打的钉子是将“合适”的数值放到这些关键位置。 现在,既然我们会在不久之后做cumsum ,如果你仔细考虑,你需要differentiated的diff values版本,这样cumsum就会带回我们的values 。 由于这些差异值将被放置在由runlens距离分隔的位置处的零点阵列上,因此在使用cumsum我们将每个vals元素重复runlens次数作为最终输出。

解决方案代码

这是实施上述所有步骤的实现 –

%// Calculate cumsumed values of runLengths. %// We would need this to initialize zeros array and find key positions later on. clens = cumsum(runlens) %// Initalize zeros array array = zeros(1,(clens(end))) %// Find key positions/indices key_pos = [1 clens(1:end-1)+1] %// Find appropriate values app_vals = diff([0 vals]) %// Map app_values at key_pos on array array(pos) = app_vals %// cumsum array for final output output = cumsum(array)

预先分配Hack

可以看出,上面列出的代码使用了预分配零。 现在,根据这个UNDOCUMENTED MATLAB blog on faster pre-allocation ,可以实现更快的预分配,

`array(clens(end)) = 0` instead of `array = zeros(1,(clens(end)))`

包装:功能代码

总结一切,我们将有一个紧凑的功能代码来实现这种运行长度解码,

function out = rle_cumsum_diff(vals,runlens) clens = cumsum(runlens); idx(clens(end))=0; idx([1 clens(1:end-1)+1]) = diff([0 vals]); out = cumsum(idx); return;

标杆

基准代码

下面列出的是基准代码,用于比较本文中所述的cumsum+diff方法的运行时间和加速比在MATLAB 2014B上的其他cumsum-only方法 –

datasizes = [reshape(linspace(10,70,4).'*10.^(0:4),1,[]) 10^6 2*10^6]; %//' fcns = {'rld_cumsum','rld_cumsum_diff'}; %// approaches to be benchmarked for k1 = 1:numel(datasizes) n = datasizes(k1); %// Create random inputs vals = randi(200,1,n); runs = [5000 randi(200,1,n-1)]; %// 5000 acts as an aberration for k2 = 1:numel(fcns) %// Time approaches tsec(k2,k1) = timeit(@() feval(fcns{k2}, vals,runs), 1); end end figure, %// Plot runtimes loglog(datasizes,tsec(1,:),'-bo'), hold on loglog(datasizes,tsec(2,:),'-k+') set(gca,'xgrid','on'),set(gca,'ygrid','on'), xlabel('Datasize ->'), ylabel('Runtimes (s)') legend(upper(strrep(fcns,'_',' '))),title('Runtime Plot') figure, %// Plot speedups semilogx(datasizes,tsec(1,:)./tsec(2,:),'-rx') set(gca,'ygrid','on'), xlabel('Datasize ->') legend('Speedup(x) with cumsum+diff over cumsum-only'),title('Speedup Plot')

rld_cumsum.m相关功能代码:

function out = rld_cumsum(vals,runlens) index = zeros(1,sum(runlens)); index([1 cumsum(runlens(1:end-1))+1]) = 1; out = vals(cumsum(index)); return;

运行时间和加速计划

GpYPR.png

RRKcR.png

结论

提出的方法似乎给了我们一个明显的加速超过cumsum-only方法,这是约3x !

为什么这个新的基于cumsum+diff的方法比以前的cumsum-only方法更好?

那么,理由的精髓在于需要将“累积”值映射到vals的cumsum-only方法的最后一步。 在新的基于cumsum+diff的方法中,我们正在执行diff(vals)而对于其中的MATLAB只处理n元素(其中n是runLengths的数量)与sum(runLengths)元素的映射相比, cumsum-only这个方法,这个数字必须比n多很多倍,因此这个新方法的显着加速!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值