我正在寻找一种快速计算的方法。
(1:N)'*(1:N)
对于相当大的N,我感觉问题的对称性使得实际执行乘法和加法是浪费的。
(1:N)'*(1:N)
对于相当大的N,我感觉问题的对称性使得实际执行乘法和加法是浪费的。
/* xtrx.c: calculates x'*x taking advantage of the symmetry.
Peter Boettcher <email removed>
Last modified: <Thu Jan 23 13:53:02 2003> */
#include "mex.h"
const double one = 1;
const double zero = 0;
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
double *x, *z;
int i, j, mrows, ncols;
if(nrhs!=1) mexErrMsgTxt("One input required.");
x = mxGetPr(prhs[0]);
mrows = mxGetM(prhs[0]);
ncols = mxGetN(prhs[0]);
plhs[0] = mxCreateDoubleMatrix(ncols,ncols, mxREAL);
z = mxGetPr(plhs[0]);
/* Call the FORTRAN BLAS routine for rank k update */
dsyrk_("U", "T", &ncols, &mrows, &one, x, &mrows, &zero, z, &ncols);
/* Result is in the upper triangle. Copy it down the lower part */
for(i=0; i<ncols; i++)
for(j=i+1; j<ncols; j++)
z[i*ncols + j] = z[j*ncols + i];
}
v'*v
(或使用调用更适当的BLAS中对称秩k更新函数的MEX包装器)要慢得多。无论如何,这里有几个仅使用MATLAB的解决方案:% test vector
N = 1e3;
v = 1:N;
% compute upper triangle of product
[ii, jj] = find(triu(ones(N)));
upperMask = false(N,N);
upperMask(ii + N*(jj-1)) = true;
Mu = zeros(N);
Mu(upperMask) = v(ii).*v(jj); % other lines always the same computation
% validate
M = v'*v;
isequal(triu(M),Mu)
下面这种方式不会比朴素方法更快,但是这里提供另一种使用 bsxfun
计算下三角的解决方案:
Ml = bsxfun(@(x,y) [zeros(y-1,1); x(y:end)*y],v',v);
对于上半部分三角形:
Mu = bsxfun(@(x,y) [x(1:y)*y; zeros(numel(x)-y,1)],v',v);
isequal(triu(M),Mu)
对于整个矩阵,使用cumsum
的另一种解决方案(其中v=1:N
),这种方法实际上速度接近。
M = cumsum(repmat(v,[N 1]));
这比 (1:N).'*(1:N) 快3倍,如果返回一个int32
的结果是可以接受的(如果数字足够小,使用int16
代替int32
甚至更快):
N = 1000;
aux = int32(1:N);
result = bsxfun(@times,aux.',aux);
基准测试:
>> N = 1000; aux = int32(1:N); tic, for count = 1:1e2, bsxfun(@times,aux.',aux); end, toc
Elapsed time is 0.734992 seconds.
>> N = 1000; aux = 1:N; tic, for count = 1:1e2, aux.'*aux; end, toc
Elapsed time is 2.281784 seconds.
aux.'*aux
不能用于aux = int32(1:N)
。double
矩阵输出,则需要进行最终转换,此时收益非常小。>> N = 1000; aux = int32(1:N); tic, for count = 1:1e2, double(bsxfun(@times,aux.',aux)); end, toc
Elapsed time is 2.173059 seconds.
鉴于输入的特殊有序结构,考虑N=4的情况。
(1:4)'*(1:4) = [1 2 3 4
2 4 6 8
3 6 9 12
4 8 12 16]