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

前端 未结 3 1597
迷失自我
迷失自我 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:09

    How to vectorize without knowing how to vectorize:

    First, I'll only discuss vectorizing the first double loop, you can follow the same logic for the second loop.

    I tried to show a thought process from scratch, so though the final answer is just 2 lines long, it is worthwhile to see how a beginner can try to obtain it.

    First, I recommend "massaging" the code in simple cases, to get a feel for it. For example, I've used n=3 and v=1:6 and run the first loop once, this is how B looks like:

    [N M]=size(B)
    N =
         9
    M =
        27
    
    imagesc(B); 
    

    enter image description here

    So you can see we get a staircase like matrix, which is pretty regular! All we need is to assign the right matrix index to the right value of v and that's it.

    There are many ways to achieve that, some more elegant than others. One of the simplest ways is to use the function find:

    pos=[find(B==v(1)),find(B==v(2)),find(B==v(3)),...
         find(B==v(4)),find(B==v(5)),find(B==v(6))]
    
    pos =
         1    10    19    28    37    46
        29    38    47    56    65    74
        57    66    75    84    93   102
        85    94   103   112   121   130
       113   122   131   140   149   158
       141   150   159   168   177   186
       169   178   187   196   205   214
       197   206   215   224   233   242
    

    The values above are the linear indices of matrix B where values of v were found. Each column represents the linear index of a specific value of v in B. For example, indices [1 29 57 ...] all contain the value v(1), etc... Each row contains v entirely, so, indices [29 38 47 56 65 74] contain v=[v(1) v(2) ... v(6)]. You can notice that for each row the difference between indices is 9, or, each index is separated with a step size N, and there are 6 of them, which is just the length of vector v (also obtained by numel(v)). For the columns, the difference between adjacent elements is 28, or, the step size is M+1.

    We shall simply need to assign the values of v in the proper indices according to this logic. one way is to write each "row":

    B([1:N:numel(v)*N]+(M+1)*0)=v;
    B([1:N:numel(v)*N]+(M+1)*1)=v;
    ...
    B([1:N:numel(v)*N]+(M+1)*(N-2))=v;
    

    But that is impractical for big N-2, so you can do it in a for loop if you really want:

    for kk=0:N-2;
         B([1:N:numel(v)*N]+(M+1)*kk)=v;
    end
    

    Matlab offers a more efficient way to get all the indices at once using bsxfun (this replaces the for loop), for example:

    ind=bsxfun(@plus,1:N:N*numel(v),[0:(M+1):M*(N-1)+1]')
    

    so now we can use ind to assign v into the matrix N-1 times. For that we need to "flatten" ind into a row vector:

    ind=reshape(ind.',1,[]);
    

    and concatenate v to itself N-1 times (or make N-1 more copies of v):

    vec=repmat(v,[1 N-1]);
    

    finally we get the answer:

    B(ind)=vec;
    

    Making a long story short, and writing it all compactly, we get a 2 line solution (given size B is already known: [N M]=size(B)) :


    ind=bsxfun(@plus,1:N:N*numel(v),[0:(M+1):M*(N-1)+1]');
    B(reshape(ind.',1,[]))=repmat(v,[1 N-1]);
    

    For n=9 the vectorized code is ~850 faster in my machine. (small n will be less significant)

    Since the matrix obtained is mostly made up from zeros, you don't need to assign these to a full matrix, instead use a sparse matrix, Here's the full code for that (pretty similar):

    N=3^(n-1);
    M=3^n;
    S=sparse([],[],[],N,M);
    ind=bsxfun(@plus,1:N:N*numel(v),[0:(M+1):M*(N-1)+1]');
    S(reshape(ind.',1,[]))=repmat(v,[1 N-1]);
    

    For n=10 I could only run the sparse matrix code (out of memory otherwise), and in my machine it took ~6 seconds.

    Now try to apply this to the second loop...

提交回复
热议问题