所以在Matlab中,我说我有一个大小为N乘N的矩阵X,而我是一个大小为1的逻辑索引向量。然后我可以做
sum(X(i,i))
问题是它等同于首先为
分配内存Y=X(i,i),
然后计算Y上的总和,并删除Y.我是对的吗? (Hoki的回答表明它是对的。)
在没有(隐式)创建Y的情况下,是否有更快的方法来计算总和?如果Y很大,则可以在内存操作中消耗大量时间。换句话说,是否可以执行以下操作:
S=zeros(1,nnz(i));
for k=find(i)
for j=find(i)
S(k)=S(k)+X(j,k);
end
end
通过这种方式,除了X之外我们需要的所有内存都是向量S - 我们不需要为大Y分配内存。当然,循环可能很慢,但你得到了我的想法。
答案 0 :(得分:3)
你对内存管理的运作方式有太多假设。
<强>定时:强>
我用timeit运行了一个基准测试。从N = 10到N = 20000,两种形式的执行时间绝对存在无明显差异。
此外,如果我关闭JIT加速度,我仍会得到相同的结果...所以优化可能只是Matlab lazy-copy
行为的结果。
内存使用情况:
在记忆方面,似乎有所不同。间接方法(使用临时变量)似乎为此临时变量分配内存(分配的大小与临时变量的大小完全对应)。另一方面,direct方法不需要任何额外的内存分配来返回结果。
这达到了我对这些事情的掌握。我不够专业,不能假装解释为什么这种内存使用差异不会导致时序差异。我知道记忆力很快,但对于N
的高阶,我认为它会有所作为。显然不是......
更多信息:
有关Matlab内存管理的更多详细信息,请您在Matlab上阅读Loren的这篇文章:
Memory Management for Functions and Variables
或者如果您想阅读更深入的机制测试:
Internal Matlab memory optimizations
基准测试结果:
基准代码:
function ExecTimes = benchmark_sumcol
%// prepare logarithmic progression (up to what my 16GB RAM can take)
nOrder = (1:9).' * 10.^(1:3) ; nOrder = [nOrder(:) ; 10000 ; 20000] ; %'
npt = numel(nOrder) ;
ExecTimes = zeros( npt , 2 ) ;
for k = 1:npt
%// Sample data
N = nOrder(k) ;
X = rand(N) ;
ci = logical(randi([0 1],1,N)) ;
%// Benchmark
f1 = @() direct_sum(X,ci) ;
f2 = @() indirect_sum(X,ci) ;
ExecTimes(k,1) = timeit( f1 ) ;
ExecTimes(k,2) = timeit( f2 ) ;
clear X ci
disp(N)
end
function R = direct_sum(X,ci)
R = sum(X(:,ci)) ;
function R = indirect_sum(X,ci)
Y = X(:,ci) ;
R = sum(Y) ;
内存基准代码
%% // set profiler options
clear all
profile('-memory','on');
setpref('profiler','showJitLines',1);
profile on
%% // sample data
N = 1000 ;
X = rand(N) ;
ci = logical(randi([0 1],1,N)) ;
%% // Benchmark
R2 = bench_indirect_sum(X,ci) ;
R1 = bench_direct_sum(X,ci) ;
%% // result
profile viewer
p = profile('info');
profsave(p,'profile_results')
我已将loop
版本添加到测试中,但我必须稍微修改它以使其实际工作(并提供与其他版本相同的结果):
function R = bench_loop_sum(X,ci)
R = zeros(1,nnz(ci));
idxRes=1 ;
for k=find(ci)
for j=1:size(X,1)
R(idxRes)=R(idxRes)+X(j,k);
end
idxRes = idxRes+1 ;
end
结果在内存方面是好的(对于临时阵列没有额外的内存分配),但在速度方面是灾难性的:
正如我们所期望的那样,循环越多,关闭JIT就越糟糕:
现在一个简单的改变来抑制内循环使事情变得更好,但仍然有点落后于直接方式(请注意,此版本不为临时列分配内存以进行总和):
function R = bench_loop_sum(X,ci)
R = zeros(1,nnz(ci));
idxRes=1 ;
for k=find(ci)
R(idxRes) = sum(X(:,k));
idxRes = idxRes+1 ;
end
使用JIT。
答案 1 :(得分:1)
有两个答案,如果你一直在寻找完整的专栏,答案很简单
class Celsius < Temperature
def initialze(n)
# should be initialize
super(:c => n)
end
end
是一行,包含所有列的总和
然后
t=sum(X);
是你想要的。
如果您正在寻找奇怪的形状,线性指数可能正是您所寻找的。 p>
请参阅 sub2ind
首先在矩阵中创建一个线性索引(一维索引),然后直接使用该索引
列i中的六个项目(5到10)的使用总和
ans=sum(t(i))