Search code examples
matlaboptimizationparfor

parfor doesn't consider information about vectors which are used in it


This is a part of my code in Matlab. I tried to make it parallel but there is an error:

 The variable gax in a parfor cannot be classified.

I know why the error occurs. because I should tell Matlab that v is an incresing vector which doesn't contain repeated elements. Could anyone help me to use this information to parallelize the code?

v=[1,3,6,8];
ggx=5.*ones(15,14);
gax=ones(15,14);
for m=v
if m > 1 
    parfor j=1:m-1
        gax(j,m-1) = ggx(j,m-1); 
    end
end
if m<nn 
    parfor jo=m+1:15 
        gax(jo,m) = ggx(jo,m); 
    end
end
end

Solution

  • Optimizing a code should be closely related to its purpose, especially when you use parfor. The code you wrote in the question can be written in a much more efficient way, and definitely, do not need to be parallelized.

    However, I understand that you tried to simplify the problem, just to get the idea of how to slice your variables, so here is a fixed version the can run with parfor. But this is surely not the way to write this code:

    v = [1,3,6,8];
    ggx = 5.*ones(15,14);
    gax = ones(15,14);
    nn = 5;
    for m = v
        if m > 1
            temp_end = m-1;
            temp = ggx(:,temp_end);
            parfor ja = 1:temp_end
                gax(ja,temp_end) = temp(ja);
            end
        end
        if m < nn
            temp = ggx(:,m);
            parfor jo = m+1:15
                gax(jo,m) = temp(jo);
            end
        end
    end
    

    A vectorized implementation will look like this:

    v = [1,3,6,8];
    ggx = 5.*ones(15,14);
    gax = ones(15,14);
    nn = 5;
    
    m1 = v>1; % first condition with logical indexing
    temp = v(m1)-1; % get the values from v
    r = ones(1,sum(temp)); % generate a vector of indicies
    r(cumsum(temp)) = -temp+1; % place the reseting locations
    r = cumsum(r); % calculate the indecies
    r(cumsum(temp)) = temp; % place the ending points
    c = repelem(temp,temp); % create an indecies vector for the columns
    inds1 = sub2ind(size(gax),r,c); % convert the indecies to linear
    
    mnn = v<nn; % second condition with logical indexing
    temp = v(mnn)+1; % get the values from v
    r_max = size(gax,1); % get the height of gax
    r_count = r_max-temp+1; % calculate no. of rows per value in v
    r = ones(1,sum(r_count)); % generate a vector of indicies
    r([1 r_count(1:end-1)+1]) = temp; % set the t indicies
    r(cumsum(r_count)+1) = -(r_count-temp)+1; % place the reseting locations
    r = cumsum(r(1:end-1)); % calculate the indecies
    c = repelem(temp-1,r_count); % create an indecies vector for the columns
    inds2 = sub2ind(size(gax),r,c); % convert the indecies to linear
    
    gax([inds1 inds2]) = ggx([inds1 inds2]); % assgin the relevant values
    

    This is indeed quite complicated, and not always necessary. A good thing to remember, though, is that nested for loop are much slower than a single loop, so in some cases (depend on the size of the output), this will may be the fastest solution:

    for m = v
        if m > 1
            gax(1:m-1,m-1) = ggx(1:m-1,m-1);
        end
        if m<nn
            gax(m+1:15,m) = ggx(m+1:15,m);
        end
    end