Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/joomla/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Matlab如何转换稀疏矩阵?_Matlab_Bsxfun - Fatal编程技术网

Matlab如何转换稀疏矩阵?

Matlab如何转换稀疏矩阵?,matlab,bsxfun,Matlab,Bsxfun,我一直在想这个问题,但找不到一个参考:既然稀疏矩阵是以CSC(compressed sparse column,压缩稀疏列)格式存储的,那么Matlab是如何快速转换稀疏矩阵的 还验证了稀疏矩阵变换的效率: 要做到这一点(逐行访问),您可以转置矩阵,对列执行操作,然后重新传输结果……转置矩阵所需的时间可以忽略不计 后续行动(根据@Mikhail的建议进行修改): 我同意@Roger和@Milhail的观点,即设置一个标志就其接口而言足以用于许多操作,例如BLAS或稀疏BLAS操作。但在我看来,M

我一直在想这个问题,但找不到一个参考:既然稀疏矩阵是以CSC(compressed sparse column,压缩稀疏列)格式存储的,那么Matlab是如何快速转换稀疏矩阵的

还验证了稀疏矩阵变换的效率:

要做到这一点(逐行访问),您可以转置矩阵,对列执行操作,然后重新传输结果……转置矩阵所需的时间可以忽略不计

后续行动(根据@Mikhail的建议进行修改):

我同意@Roger和@Milhail的观点,即设置一个标志就其接口而言足以用于许多操作,例如BLAS或稀疏BLAS操作。但在我看来,Matlab做的是“实际的”换位。例如,我有一个大小为m*n=7984*12411的稀疏矩阵X,我想缩放每一列和每一行:

% scaling each column
t = 0;
for i = 1 : 1000
    A = X; t0 = tic;
    A = bsxfun(@times, A, rand(1,n));
    t = t + toc(t0);
end
t=0.023636秒

% scaling each row
t = 0;
for i = 1 : 1000
    A = X; t0 = tic;
    A = bsxfun(@times, A, rand(m,1));
    t = t + toc(t0);
end
t=138.3586秒

% scaling each row by transposing X and transforming back
t = 0;
for i = 1 : 1000
    A = X; t0 = tic;
    A = A'; A = bsxfun(@times, A, rand(1,m)); A = A';
    t = t + toc(t0);
end
t=19.5433秒

这意味着逐列访问要比逐行访问快。这是有意义的,因为稀疏矩阵是逐列存储的。因此,X'列缩放速度快的唯一原因应该是X实际上被转置到X'而不是设置标志

此外,如果每个稀疏矩阵都以CSC格式存储,那么简单地设置一个标志不能使X'成为CSC格式


有什么评论吗?提前谢谢。

我同意罗杰·罗兰在评论中提到的。为了支持这一建议,您可以检查BLAS接口中的一些函数,MATLAB将其用于矩阵运算。我不确定它使用的是什么实现,但既然他们使用Intel IPP进行图像处理,我想他们也可以使用Intel MKL来加快矩阵运算


这是函数的文档,它以CSC格式为稀疏矩阵求解线性方程组。请注意
transa
输入标志,它明确定义了提供的矩阵是否应被视为转置。

经过一周的探索,我对转置矩阵的内部机制的猜测是排序

假设
A
是稀疏矩阵

[I, J, S] = find(A);
[sorted_I, idx] = sort(I);
J = J(idx);
S = S(idx);
B = sparse(J, sorted_I, S);
然后
B
A
的转置


上述实现的效率大约是我的机器上Matlab内置的
转置
的一半。考虑到Matlab的内置函数是多线程的,我的猜测可能是合理的。

我意识到我玩游戏有点晚了,但我想我可以帮助阐明这个问题。转换稀疏矩阵实际上是一项简单的任务,可以在与输入矩阵中非零元素数量成比例的时间内完成。假设A是以CSC格式存储的m x n矩阵,即A由三个数组定义:

  • 长度为nnz(A)的elemsA,将非零元素存储在
  • 长度为nnz(A)的prowA,用于存储
  • pcolA,长度为n+1,使得A的j列中的所有非零元素都由范围[pcolA(j),pcolA(j+1))索引
  • 如果B表示A的转置,那么我们的目标是定义类似的数组elemsB、prowB、pcolB。为此,我们使用A的行构成B的列的事实。让tmp成为一个数组,使得tmp(1)=0,tmp(i+1)是A的行i中i=1,…,m的元素数。然后,tmp(i+1)是B的第i列中的元素数。因此,tmp的累积和与pcolB相同。现在假设tmp已被其累积和覆盖。然后可以按如下方式填充elemsB和prowB

        for j = 1,...,n
            for k = pcolA(j),...,pcolA(j + 1) - 1
                prowB(tmp(prowA(k))) = j
                elemsB(tmp(prowA(k))) = elemsA(k)
                tmp(prowA(k)) = tmp(prowA(k)) + 1
            end
        end
    
    < P >数组TMP在添加新元素时被用来索引PROWB和ELSB,然后相应地更新,将其完全写出来,我们可以在C++中编写一个MEX文件,实现转置算法:

    #include "mex.h"
    #include <vector>
    void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {     
        // check input output
        if (nrhs != 1)
           mexErrMsgTxt("One input argument required");
        if (nlhs > 1)
           mexErrMsgTxt("Too many output arguments");
    
        // get input sparse matrix A
        if (mxIsEmpty(prhs[0])) { // is A empty?
            plhs[0] = mxCreateSparse(0, 0, 0, mxREAL);
            return;
        }
        if (!mxIsSparse(prhs[0]) || mxIsComplex(prhs[0])) // is A real and sparse?
           mexErrMsgTxt("Input matrix must be real and sparse");
        double* A = mxGetPr(prhs[0]);           // real vector for A
        mwIndex* prowA = mxGetIr(prhs[0]);      // row indices for elements of A
        mwIndex* pcolindexA = mxGetJc(prhs[0]); // index into the columns
        mwSize M = mxGetM(prhs[0]);             // number of rows in A
        mwSize N = mxGetN(prhs[0]);             // number of columns in A
    
        // allocate memory for A^T
        plhs[0] = mxCreateSparse(N, M, pcolindexA[N], mxREAL);
        double* outAt = mxGetPr(plhs[0]);
        mwIndex* outprowAt = mxGetIr(plhs[0]);
        mwIndex* outpcolindexAt = mxGetJc(plhs[0]);
    
        // temp[j + 1] stores the number of nonzero elements in row j of A
        std::vector<mwSize> temp(M + 1, 0); 
        for(mwIndex i = 0; i != N; ++i) {
            for(mwIndex j = pcolindexA[i]; j < pcolindexA[i + 1]; ++j)
                ++temp[prowA[j] + 1];
        }
        outpcolindexAt[0] = 0;
        for(mwIndex i = 1; i <= M; ++i) {
            outpcolindexAt[i] = outpcolindexAt[i - 1] + temp[i];
            temp[i] = outpcolindexAt[i];
        }
        for(mwIndex i = 0; i != N; ++i) {
            for(mwIndex j = pcolindexA[i]; j < pcolindexA[i + 1]; ++j) {
                outprowAt[temp[prowA[j]]] = i;
                outAt[temp[prowA[j]]++] = A[j];
            }
        }
    }
    
    #包括“mex.h”
    #包括
    void-mexFunction(int-nlhs,mxArray*plhs[],int-nrhs,const-mxArray*prhs[]){
    //检查输入输出
    如果(nrhs!=1)
    mexErrMsgTxt(“需要一个输入参数”);
    如果(nlhs>1)
    mexErrMsgTxt(“太多输出参数”);
    //获取输入稀疏矩阵A
    如果(mxiempty(prhs[0]){//是空的?
    plhs[0]=mxCreateSparse(0,0,0,mxREAL);
    返回;
    }
    如果(!mxIsSparse(prhs[0])| | mxicomplex(prhs[0])//是实数和稀疏数?
    mexErrMsgTxt(“输入矩阵必须是实的和稀疏的”);
    double*A=mxGetPr(prhs[0]);//A的实向量
    MWDINDEX*prowA=mxGetIr(prhs[0]);//一个元素的行索引
    mwIndex*pcolindexA=mxGetJc(prhs[0]);//索引到列中
    mwSize M=mxGetM(prhs[0]);//一行中的行数
    mwSize N=mxGetN(prhs[0]);//数据中的列数
    //为^T分配内存
    plhs[0]=mxCreateSparse(N,M,pcolindexA[N],mxREAL);
    double*outAt=mxGetPr(plhs[0]);
    MWDINDEX*outprowAt=mxGetIr(plhs[0]);
    mwIndex*outpcolindexAt=mxGetJc(plhs[0]);
    //temp[j+1]存储A的第j行中非零元素的数量
    标准:向量温度(M+1,0);
    对于(MWI指数i=0;i!=N;++i){
    对于(mw指数j=pcolindexA[i];j对于(MWDINDEX i=1;i它可能只是设置了一个控制其数组访问行为的标志——在访问时交换行/列索引,并保留数据非常快。@Rogerowland请参阅我在上面添加的后续内容。谢谢。我建议做一些试验。20毫秒不是一个可靠的时间度量。@Mikhail我做了1000次迭代现在,修改问题文本above@DaKuang第一个测试是
    rand(1,n)
    ,第三个测试是
    rand(1,m)
    。此外,当您进行大量测试时,
    tic/toc
    应该放在循环之外。它们使用哪个BLAS/LAPACK实现并不重要,因为afaik几乎都是