简体   繁体   中英

Vectorization of MATLAB/Octave loop

Can this for-loop be vectorized further?

for i = 1:length(formula)
ttable(i,abs(formula(i,:))) = -1*formula(i,:);
end

Where formula is a matrix and ttable = NaN(length(formula),max(max(abs(formula)))) . Thanks!

Judging from the code, what you are doing is that for each row of ttable , you wish to use the indices accessed by abs(formula(i,:)) and set each of these locations to -1*formula(i,:) .

Noting @Divakar's clever spot, I am going to assume that each row has unique absolute values. In other words, each row should not have instances where you could have a or -a in a row, where a is any number from 1 up to size(formula,2) . The reason why is because in your computation of abs(formula(i,:)) , -a and a will then map to the same column. This will conflict and allow for overwriting into the same entry (Thanks @Divakar!)

What we can do is for each row of formula , convert these locations into column-major indices to access ttable . After, assign the corresponding values of -1*formula into ttable . In other words:

%// Find those columns that should be accessed
columnIndices = reshape(abs(formula).', 1, []);

%// For each column we are accessing, find the corresponding row
rowIndices = reshape(repmat(1:size(formula,2), size(formula, 1), 1), 1, []);

%// Find the column major indices we need to access overall
indices = sub2ind(size(formula), rowIndices, columnIndices);

%// Take those indices that we have computed above, and map them
%// to those columns we found earlier
ttable(indices) = -1*formula.';

Here is a small test I created. This is also based on the same assumption of unique absolute values that I made before:

formula = [1 2 -3 4; 4 -2 3 1; 3 2 4 -1; -4 1 2 3];
ttable = NaN(length(formula),max(max(abs(formula))));

formula =

 1     2    -3     4
 4    -2     3     1
 3     2     4    -1
-4     1     2     3


ttable =

NaN   NaN   NaN   NaN
NaN   NaN   NaN   NaN
NaN   NaN   NaN   NaN
NaN   NaN   NaN   NaN

Using your approach, we get:

for i = 1:length(formula)
    ttable(i,abs(formula(i,:))) = -1*formula(i,:);
end

ttable =

-1    -2     3    -4
-1     2    -3    -4
 1    -2    -3    -4
-1    -2    -3     4

Using my approach, we get:

columnIndices = reshape(abs(formula).', 1, []);
rowIndices = reshape(repmat(1:size(formula,2), size(formula, 1), 1), 1, []);
indices = sub2ind(size(formula), rowIndices, columnIndices);
ttable(indices) = -1*formula.';

ttable =

-1    -2     3    -4
-1     2    -3    -4
 1    -2    -3    -4
-1    -2    -3     4

If your matrix is small, then the computational overhead by doing this instead of the for loop may be larger and so this will be inefficient. However, if your matrix is larger, then this code may be faster. Either way, I think your for loop approach is still good. The JIT should kick in for for loops. If you take a look at this post here when doing some timing tests for an algorithm where a for loop was used as one of the algorithms, the for loop was one of the algorithms that was the fastest. Check here: MATLAB: Subtracting matrix subsets by specific rows

Another approach, which uses bsxfun to generate the linear indices:

ind = bsxfun(@plus, (1:size(ttable,1)).' , (abs(formula)-1)*size(ttable,1));
ttable(ind) = -formula;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM