Multiple loop variables Matlab - matlab

In C++/C, we have multiple loop variables in a single loop, like for(int i=0; int j=0; i<5; j<5; i++; j++) Is there any facility in Matlab for multiple variables loop?
And also, I'm very conscious in loop iterations computations, so does it effects the speed as I'v already a nested loop in Matlab.

MATLAB sort of supports multiple loop variables in that it supports a matrix as the loop expression. How does that work? Individual columns of the matrix are assigned to the loop variable at the beginning of each iteration.
Example code:
V = [1:1:5; 2:2:10]
for iv = V,
fprintf('iv = [%d %d];\n',iv);
end
Output:
V =
1 2 3 4 5
2 4 6 8 10
iv = [1 2];
iv = [2 4];
iv = [3 6];
iv = [4 8];
iv = [5 10];
We've achieved two loop variables here, iv(1) and iv(2), which are specified by the rows of the matrix used as the loop expression. Note that the array can be any type (e.g. string, cell, struct, etc.).
Summary
Pre-define each iteration of the loop variables, and store them as the rows of the matrix. Inside the loop, the loop variable will contain a column of the matrix.
Side note
I'm guessing that this convention is a consequence of the fact that the colon operator produces an array by horizontal concatenation rather than vertical. Just consider what happens in the following case:
for ii = (1:3).', numel(ii), end
You might be expecting three iterations, each indicating numel(ii)=1, but you only get one iteration and the loop reports:
ans =
3
The problem is clear if you are expecting ii to be a scalar.
Terminology
for loop_variable = loop_expression, statement, ..., statement end

MATLAB doesn't have the capability of doing multiple loop variables, you will have to use nested for-loops. That said, one of MATLAB's greatest strengths is efficiently applying a function across an array.
For example:
a = zeros(1,5);
for i=1:5
a(i) = sin(i);
end
b = sin(1:5);
In the above example a & b will be identical, but calculating b doesn't require an explicit for-loop. There are times when explicit for-loops (including nested loops) are necessary (like running a simulation via the sim command), but since you are concerned about the time to compute the loop iterations, my guess is you aren't running time-intensive tasks like a massive simulation.
So rather than using nested for-loops, I'd look into setting up your functions to work with arrays and input your "loop variables" as the arrays. Look into the commands meshgrid & griddata to help create those arrays.

As chappjc pointed out, and as MathWorks states in the documentation, each iteration of a for loop takes the next column of the iterator. Thus, to iterate through a column vector, for example, one must transpose it (i.e. for ii = [1; 1; 2; 3; 5]'), otherwise ii is equal to the column vector, all at once.
And merely to extend chappjc's excellent answer, you may take advantage of this behavior with cells, also, where you might have some differently sized strings, in addition to wanting a numeric iterator, and then you can deal them to variables so you don't have to do as much indexing. Here is a crude example:
figure(1)
imageList = {};
for ii = [{somePath; someDirListing; 1}, {anotherPath; anotherDirListing; 2}] % Each iteration takes one column
[pathname, images, iPos] = deal(ii{:});
for iImage = images
img = imread(fullfile(pathname, iImage));
imagesc(img)
axis image
if iPos == 1
title(['This is a left image, titled ' iImage])
else
title(['This is a right image, titled ' iImage])
end
pause(1)
end
end

Related

Efficient generation of permutation matrices in MATLAB

I'm trying to generate a 100-by-5 matrix where every line is a permutation of 1..100 (that is, every line is 5 random numbers from [1..100] without repetitions).
So far I've only been able to do it iteratively with a for-loop. Is there a way to do it more efficiently (using fewer lines of code), without loops?
N = 100;
T = zeros(N, 5);
for i = 1:N
T(i, :) = randperm(100, 5);
end
Let
N = 100; % desired number of rows
K = 5; % desired number of columns
M = 100; % size of population to sample from
Here's an approach that's probably fast; but memory-expensive, as it generates an intermediate M×N matrix and then discards N-K rows:
[~, result] = sort(rand(N, M), 2);
result = result(:, 1:K);
There is very little downside to using a loop here, at least in this minimal example. Indeed, it may well be the best-performing solution for MATLAB's execution engine. But perhaps you don't like assigning the temporary variable i or there are other advantages to vectorization in your non-minimal implementation. Consider this carefully before blindly implementing a solution.
You need to call randperm N times, but each call has no dependency on its position in the output. Without a loop index you will need something else to regulate the number of calls, but this can be just N empty cells cell(N,1). You can use this cell array to evaluate a function that calls randperm but ignores the contents (or, rather, lack of contents) of the cells, and then reassemble the function outputs into one matrix with cell2mat:
T = cell2mat(cellfun(#(~) {randperm(100,5)}, cell(N,1)));

Matlab: creating vector from 2 input vectors [duplicate]

I'm trying to insert multiple values into an array using a 'values' array and a 'counter' array. For example, if:
a=[1,3,2,5]
b=[2,2,1,3]
I want the output of some function
c=somefunction(a,b)
to be
c=[1,1,3,3,2,5,5,5]
Where a(1) recurs b(1) number of times, a(2) recurs b(2) times, etc...
Is there a built-in function in MATLAB that does this? I'd like to avoid using a for loop if possible. I've tried variations of 'repmat()' and 'kron()' to no avail.
This is basically Run-length encoding.
Problem Statement
We have an array of values, vals and runlengths, runlens:
vals = [1,3,2,5]
runlens = [2,2,1,3]
We are needed to repeat each element in vals times each corresponding element in runlens. Thus, the final output would be:
output = [1,1,3,3,2,5,5,5]
Prospective Approach
One of the fastest tools with MATLAB is cumsum and is very useful when dealing with vectorizing problems that work on irregular patterns. In the stated problem, the irregularity comes with the different elements in runlens.
Now, to exploit cumsum, we need to do two things here: Initialize an array of zeros and place "appropriate" values at "key" positions over the zeros array, such that after "cumsum" is applied, we would end up with a final array of repeated vals of runlens times.
Steps: Let's number the above mentioned steps to give the prospective approach an easier perspective:
1) Initialize zeros array: What must be the length? Since we are repeating runlens times, the length of the zeros array must be the summation of all runlens.
2) Find key positions/indices: Now these key positions are places along the zeros array where each element from vals start to repeat.
Thus, for runlens = [2,2,1,3], the key positions mapped onto the zeros array would be:
[X 0 X 0 X X 0 0] % where X's are those key positions.
3) Find appropriate values: The final nail to be hammered before using cumsum would be to put "appropriate" values into those key positions. Now, since we would be doing cumsum soon after, if you think closely, you would need a differentiated version of values with diff, so that cumsum on those would bring back our values. Since these differentiated values would be placed on a zeros array at places separated by the runlens distances, after using cumsum we would have each vals element repeated runlens times as the final output.
Solution Code
Here's the implementation stitching up all the above mentioned steps -
% Calculate cumsumed values of runLengths.
% We would need this to initialize zeros array and find key positions later on.
clens = cumsum(runlens)
% Initalize zeros array
array = zeros(1,(clens(end)))
% Find key positions/indices
key_pos = [1 clens(1:end-1)+1]
% Find appropriate values
app_vals = diff([0 vals])
% Map app_values at key_pos on array
array(pos) = app_vals
% cumsum array for final output
output = cumsum(array)
Pre-allocation Hack
As could be seen that the above listed code uses pre-allocation with zeros. Now, according to this UNDOCUMENTED MATLAB blog on faster pre-allocation, one can achieve much faster pre-allocation with -
array(clens(end)) = 0; % instead of array = zeros(1,(clens(end)))
Wrapping up: Function Code
To wrap up everything, we would have a compact function code to achieve this run-length decoding like so -
function out = rle_cumsum_diff(vals,runlens)
clens = cumsum(runlens);
idx(clens(end))=0;
idx([1 clens(1:end-1)+1]) = diff([0 vals]);
out = cumsum(idx);
return;
Benchmarking
Benchmarking Code
Listed next is the benchmarking code to compare runtimes and speedups for the stated cumsum+diff approach in this post over the other cumsum-only based approach on MATLAB 2014B-
datasizes = [reshape(linspace(10,70,4).'*10.^(0:4),1,[]) 10^6 2*10^6]; %
fcns = {'rld_cumsum','rld_cumsum_diff'}; % approaches to be benchmarked
for k1 = 1:numel(datasizes)
n = datasizes(k1); % Create random inputs
vals = randi(200,1,n);
runs = [5000 randi(200,1,n-1)]; % 5000 acts as an aberration
for k2 = 1:numel(fcns) % Time approaches
tsec(k2,k1) = timeit(#() feval(fcns{k2}, vals,runs), 1);
end
end
figure, % Plot runtimes
loglog(datasizes,tsec(1,:),'-bo'), hold on
loglog(datasizes,tsec(2,:),'-k+')
set(gca,'xgrid','on'),set(gca,'ygrid','on'),
xlabel('Datasize ->'), ylabel('Runtimes (s)')
legend(upper(strrep(fcns,'_',' '))),title('Runtime Plot')
figure, % Plot speedups
semilogx(datasizes,tsec(1,:)./tsec(2,:),'-rx')
set(gca,'ygrid','on'), xlabel('Datasize ->')
legend('Speedup(x) with cumsum+diff over cumsum-only'),title('Speedup Plot')
Associated function code for rld_cumsum.m:
function out = rld_cumsum(vals,runlens)
index = zeros(1,sum(runlens));
index([1 cumsum(runlens(1:end-1))+1]) = 1;
out = vals(cumsum(index));
return;
Runtime and Speedup Plots
Conclusions
The proposed approach seems to be giving us a noticeable speedup over the cumsum-only approach, which is about 3x!
Why is this new cumsum+diff based approach better than the previous cumsum-only approach?
Well, the essence of the reason lies at the final step of the cumsum-only approach that needs to map the "cumsumed" values into vals. In the new cumsum+diff based approach, we are doing diff(vals) instead for which MATLAB is processing only n elements (where n is the number of runLengths) as compared to the mapping of sum(runLengths) number of elements for the cumsum-only approach and this number must be many times more than n and therefore the noticeable speedup with this new approach!
Benchmarks
Updated for R2015b: repelem now fastest for all data sizes.
Tested functions:
MATLAB's built-in repelem function that was added in R2015a
gnovice's cumsum solution (rld_cumsum)
Divakar's cumsum+diff solution (rld_cumsum_diff)
knedlsepp's accumarray solution (knedlsepp5cumsumaccumarray) from this post
Naive loop-based implementation (naive_jit_test.m) to test the just-in-time compiler
Results of test_rld.m on R2015b:
Old timing plot using R2015a here.
Findings:
repelem is always the fastest by roughly a factor of 2.
rld_cumsum_diff is consistently faster than rld_cumsum.
repelem is fastest for small data sizes (less than about 300-500 elements)
rld_cumsum_diff becomes significantly faster than repelem around 5 000 elements
repelem becomes slower than rld_cumsum somewhere between 30 000 and 300 000 elements
rld_cumsum has roughly the same performance as knedlsepp5cumsumaccumarray
naive_jit_test.m has nearly constant speed and on par with rld_cumsum and knedlsepp5cumsumaccumarray for smaller sizes, a little faster for large sizes
Old rate plot using R2015a here.
Conclusion
Use repelem below about 5 000 elements and the cumsum+diff solution above.
There's no built-in function I know of, but here's one solution:
index = zeros(1,sum(b));
index([1 cumsum(b(1:end-1))+1]) = 1;
c = a(cumsum(index));
Explanation:
A vector of zeroes is first created of the same length as the output array (i.e. the sum of all the replications in b). Ones are then placed in the first element and each subsequent element representing where the start of a new sequence of values will be in the output. The cumulative sum of the vector index can then be used to index into a, replicating each value the desired number of times.
For the sake of clarity, this is what the various vectors look like for the values of a and b given in the question:
index = [1 0 1 0 1 1 0 0]
cumsum(index) = [1 1 2 2 3 4 4 4]
c = [1 1 3 3 2 5 5 5]
EDIT: For the sake of completeness, there is another alternative using ARRAYFUN, but this seems to take anywhere from 20-100 times longer to run than the above solution with vectors up to 10,000 elements long:
c = arrayfun(#(x,y) x.*ones(1,y),a,b,'UniformOutput',false);
c = [c{:}];
There is finally (as of R2015a) a built-in and documented function to do this, repelem. The following syntax, where the second argument is a vector, is relevant here:
W = repelem(V,N), with vector V and vector N, creates a vector W where element V(i) is repeated N(i) times.
Or put another way, "Each element of N specifies the number of times to repeat the corresponding element of V."
Example:
>> a=[1,3,2,5]
a =
1 3 2 5
>> b=[2,2,1,3]
b =
2 2 1 3
>> repelem(a,b)
ans =
1 1 3 3 2 5 5 5
The performance problems in MATLAB's built-in repelem have been fixed as of R2015b. I have run the test_rld.m program from chappjc's post in R2015b, and repelem is now faster than other algorithms by about a factor 2:

How can I shift array element using a for loop in Matlab?

I'm trying to shift all the elements of an array to the left, so that the first element would become the last element, the second becomes the first, the third the second, etc. I know about the circshift commands, but I would like to do this using a for loop.
Here's what I did.
old=[]
n=length(old)
for i=1;i<(n-1);i=i+1;
for j=2;j<n;j=j+1;
new(j)=old(i)
end
end
But it of course didn't work. I'm having trouble figuring out to make an array of n elements, without specifying n, which is why I used old=[], but I think that created an array of 0 elements.
How can I make this code work?
If you want to avoid specifying the n length of the array, you have to give it as an input argument in a function.
For example you can do something like this:
function new = shiftLeft(old)
n = length(old);
for i =1:n
new(i) = old(mod(i,n)+1);
end
return
So with this one, if you have an array for example old = [1 2 3 4]; you can will get something like new = [2 3 4 1];
mod(a,b) is the modulo operator, you can find more information if you type help mod.
So your irst step is to learn how to specify a for loop in Matlab, what you have is like C syntax. This is not Matlab syntax at all.
The following is how to do it using forloops but this is not good matlab programming. You could easily do it without loops too.
vec = 1:10;
temp = [];
shiftby = 2;
for ii = 1:shiftby %Each iteration shifts by one
temp = vec(end); %Store the last element of vec
for jj = size(vec, 2):-1:2; %inner loop must shift each element from the end to element 2
vec(jj) = vec(jj-1);
end
vec(1) = temp; %put the old end value at the beginning
end
but you could also just do this which is a much more Matlabesque way to code it:
vec = [vec(end - shiftby + 1: end), vec(1:end - shiftby)]

Combination of colon-operations in MATLAB

I have a question concerning the colon operator and expansion of vectors in MATLAB. My problem is to understand how the following line of code expands, to be able to use it for other sequences. The line of MATLAB code is:
a(1:2:5) = 1:-4:-7
Note that a is not defined before the expansion. This returns the vector
a = 1 0 3 0 -7
I know how the colon operator works with {start}:{step}:{stop}, my problem is to understand how and why the combination of a(1:2:5)and 1:-4:-7 returns a vector of five elements with zeros in position 2 and 5?
Whenever Matlab detects you're indecing to an element outside the current bounds of the matrix/array, it will automatically pad the missing elements with zeros:
>> clear b; b(10) = 5
b =
0 0 0 0 0 0 0 0 0 5
This feature is both very useful, and very dangerous. It is useful for the fact declarations can be made very easy, such as your own case. You can create a whole array of custom-made classes by issuing something like
myClassArray(500) = myClass(1, 2);
which is infinitely better than something like
% cannot pre-allocate (zeros() or ones() give double/uint8/..., not myClass)
for ii = 1:499
myClassArray(ii) = myClass; % so, growing array
end
myClassArray(500) = myClass(1,2);
But, growing arrays can be hard to spot:
a = zeros(10,1);
for ii = 1:10
a(ii+1) = rand;
end
which can make performance drop tremendously. Also, when you translate code prototyped in Matlab to a statically-typed language like C++, copying this code will result in buffer overflows and thus segfaults.
Now, going back to your case:
clear a; a(1:2:5) = 1:-4:-7
The 1:2:5 will expand to the array [1 3 5], and the 1:-4:-7 will give the values [1 -3 -7]. Since the variable a does not exist yet, Matlab will create a new one and fill the elements [1 3 5] with the values [1 -3 -7]. The indices that have been skipped in order to initialize variable a (namely, [2 4]) will then have been initialized automatically to zero.
If you're familiar with Python, it's a bit like the syntax to assign multiple values to multiple variables
x,y = 1,2
But in your Matlab case, these different variables are indices to a non-existent array, which requires "filling the holes with something" to make it a valid, consistent array.
Does this make things clear?
when you define a(1:2:5), it creates a size 5 vector (zero-valued), and selecting odd indexed(3 of them exists) cells. 1:-4:-7 creates three values (not five). Finally your selected three cells are filled with data of 3 values coming from 1:-4:-7

How to make random matrix whose rows must all sum <=11 and which cannot contain consecutive triplets of 0-0-0 in any row

I want to make an array called result, which has dimensions (14,12,10) and has values random[0 2], but it should not contain 0 more than three consecutive times in each row (dimension 2), and the sum of all values in each row must be <= 11.
This is my current approach:
jum_kel = 14;
jum_bag = 12;
uk_pop = 10;
for ii = 1:uk_pop,
libur(:,:,ii) = randint(jum_kel,jum_bag,[0 2]); %#initialis
sum_libur(1,:,ii) = sum(libur(:,:,ii),2); %#sum each row
end
for jj = 1:jum_kel
while sum_libur(1,jj,ii) > 11, %# first constraint : sum each row should be <=11,
libur(jj,:,ii) = randint(1,jum_bag,[0 2])
sum_libur(1,:,ii)= sum(libur(:,:,ii),2);
for kk = 1:jum_bag
if kk>2
o = libur(jj,kk,ii)+libur(jj,kk-1,ii)+libur(jj,kk-2)
while kk>2 && o==0 %# constraint 2: to make matrix will not contain consecutive triplets (0-0-0) in any row.
libur(jj,:,ii) = randint(1,jum_bag,[0 2]);
sum_libur(1,:,ii)= sum(libur(:,:,ii),2);
end
end
end
end
end
but this is extremely slow...Does anyone see a faster method?
(sidenote: A matrix does not have 3 dimensions: that would be a tensor, in which case the concept of "row" is not well-defined.)
The easiest way is to use Rejection Sampling. Normally this might be slow, and even though you don't mention it, I'd worry this code might occur in a performance-critical section of your program. Nevertheless, everything is okay, since the chance of a 14 3-sided coinflips in a row containing the substring 0-0-0 is fairly small. Even it's an issue, since the matrix is (supposedly) uniformly distributed, its elements must also be independently distributed, so you can sample each row separately, rejecting and recreating any row with 0-0-0 in a row or which has a sum <= 11.
As indicated by #ninjagecko, rejecting and recreating is the most obvious (if not the only) way to go here. In that light, I think this'll do nicely:
R = 14;
C = 12;
T = 10;
result = zeros(C,R*T);
for ii = 1:(R*T)
done = false;
while ~done
newRow = randi([0 2],C,1);
done = ...
(sum(newRow)<12) && ...
(~any(diff([0;find(newRow);C+1])>3));
end
result(:,ii) = newRow;
end
result = permute(reshape(result,C,R,T), [2 1 3]);
Note that <12 equals <=11 for integer math (and >3 equals >=4), but requires one less check and is thus faster. The variable newRow is created as a column vector, since such things are better organized in memory and can be checked faster. 3D arrays are generally slower to assign to than 2D matrices, therefore everything is kept 2D until after all operations. The most computationally intense check (~any(diff(find(newRow))>3)) is done last, so that short-circuiting (&&) may render its evaluation unnecessary. Both loops are small and fulfil all conditions to be compiled to machine code by Matlab's JIT.
So this is pretty close to optimized, and will be pretty fast. Unless someone comes up with an entirely different algorithm for this, I believe this is pretty close to the theoretical maximum speed in Matlab. If you need to go faster, you'll have to switch to C (which will allow optimization of the constraint checks).
For simply finding a series of numbers in an array, you can (ab)use strfind. When indexing into a multidimensional array, you can also combine subindices and linear indexing to the remaining dimensions (used in the assignment result(:,ii) = newRow):
result = NaN(12,14,10);
for ii = 1:14*10
while 1
newRow = randi([0 2],12,1);
if isempty(strfind(newRow',[0 0 0])) && sum(newRow)<=11
result(:,ii) = newRow;
break;
end
end
end
result = permute(result, [2 1 3]);