Improving MATLAB Matrix Construction Code : Or, code Vectorization for beginners

前端 未结 3 1600
迷失自我
迷失自我 2020-12-09 13:32

I wrote a program in order to construct a portion of a 3-Band Wavelet Transform Matrix. However, given that the size of the matrix is 3^9 X 3^10, it takes a while for MATLAB

3条回答
  •  遥遥无期
    2020-12-09 14:10

    While your matrix has huge dimensions it's also very "sparse", which means that most of it's elements are zeros. To improve performance you can make use of MATLAB's sparse matrix support by ensuring that you only operate on the non-zero parts of your matrix.

    Sparse matrices in MATLAB can be built efficiently by constructing the coordinate form of the sparse matrix. This means that three arrays, defining the row, column and value for each non-zero entry in the matrix must be defined. This means that rather than assigning values via the conventional A(i,j) = x syntax, we would instead append that non-zero entry onto our sparse indexing structure:

    row(pos+1) = i;
    col(pos+1) = j;
    val(pos+1) = x;
    % pos is the current position within the sparse indexing arrays!
    

    Once we have the full set of non-zeros in our sparse indexing arrays, we can use the sparse command to build the matrix.

    For this problem, we add a maximum of six non-zero entries for each row, allowing us to allocate the sparse indexing arrays in advance. The variable pos keeps track of our current position in the indexing arrays.

    rows = 3^(n-1);
    cols = 3^(n+0);
    
    % setup the sparse indexing arrays for non-
    % zero elements of matrix B
    row = zeros(rows*6,1);
    col = zeros(rows*6,1);
    val = zeros(rows*6,1);
    pos = +0;
    

    We can now build the matrix by adding any non-zero entries to the sparse indexing arrays. Since we only care about non-zero entries, we only loop over the non-zero parts of the matrix as well.

    I've left the logic for the last row for you to fill in!

    for j = 1 : 3^(n-1)
        if (j < 3^(n-1))
    
    % add entries for a general row
        for k = max(1,3*(j-1)+1) : min(3^n,3*(j-1)+6)             
            pos = pos+1;
            row(pos) = j;
            col(pos) = k;
            val(pos) = v(k-3*(j-1));                
        end
    
        else
    
    % add entries for final row - todo!!
    
        end
    end
    

    Since we don't add six non-zeros for every row, we may have over-allocated the sparse indexing arrays, so we trim them down to the size that's actually used.

    % only keep the sparse indexing that we've used
    row = row(1:pos);
    col = col(1:pos);
    val = val(1:pos);
    

    The final matrix can now be built using the sparse command.

    % build the actual sparse matrix
    B = sparse(row,col,val,rows,cols);
    

    The code can be run by collating the snippets above. For n = 9 we get the following results (for comparison, I've also included results for the bsxfun based approach suggested by natan):

    Elapsed time is 2.770617 seconds. (original)
    Elapsed time is 0.006305 seconds. (sparse indexing)
    Elapsed time is 0.261078 seconds. (bsxfun)
    

    The original code runs out of memory for n = 10, though both sparse approaches are still usable:

    Elapsed time is 0.019846 seconds. (sparse indexing)
    Elapsed time is 2.133946 seconds. (bsxfun)
    

提交回复
热议问题