Double for loop, how to set non-continuous index? - matlab

If I want to construct a double for loop, but for index k I don't want it to be continuous index but like [1,2,4,7]. I tried to do the following, and it did not work.
for i=1:100
for k=1:2:4:7;
b(i)=i*k;
end
end
Anyone could help me deal with that?

When you want to construct an array, you don't want to necessarily use the colon (:) operator unless you want to create a range of values (like you do when you want i to be all values between 1 and 100), instead you want to use square brackets ([]) with comma separators to explicitly create an array of discrete values.
k = [1,2,4,7];
Now that you do this you can specify your loop like you had it with this small substitution for the values of k
kvalues = [1,2,4,7];
for i = 1:100
for k = 1:numel(kvalues)
b(i) = i * kvalues(k);
end
end
Notice that I have defined kvalues once outside of the loop so that it is not created every iteration through the outer loop (thanks to #dfri for pointing this oversight out)
The way that you have your loop written, you're actually over-writing the value of b(i) every time through the inner loop. I'm not sure if that's what you intended to do. If it is, then you can reduce your loop to the following:
b = k(end) * (1:100);
Otherwise, if you meant to have it be b(i,k) = i * k, you could rewrite this with bsxfun.
b = bsxfun(#mtimes, [1,2,4,7], (1:100).');

The syntax k=1:2:4:7 will not work as you intend. Usually we make use of the "two colon" syntax to describe a non-default (1) step size from the given start to end values, k = start:stepSize:end. Using an additional colon here even yields a Matlab warning ("third colon probably not intended?").
One possible workaround is to let your "non-continuous" indices reside in a vector and extract members of this vector in the inner for loop as follows
nonContIndex = [1; 2; 4; 7];
numIndices = numel(nonContIndex);
b = zeros(100,numIndices);
for i=1:100
for k=1:numIndices
b(i,k)=i*nonContIndex(k);
end
end
As noted by comments and the other answer: if b is simply a vector, your original loop will overwrite the b(i):th entry for each run of the inner loop. The above assumes that you in fact want a 2D matrix as a result.

Related

Matlab: Automatically create cell array with name with meaning

I would like to name variable (type double) in the following way:
k0 = D(1,1);
k1 = D(2,2);
k2 = D(3,3);
k3 = D(4,4);
k4 = D(5,5);
k5 = D(6,6);
k6 = D(7,7);
k7 = D(8,8);
...
up to k99 automatically using for loop. So I see that I should use array or cell instead of double variable using eval as it is slow. But if I should use array or cell instead of double variable, I have to start at k{1} or k(1), which loses the meaning as I want exactly that k0 refers to D(1,1), i.e. the number in my variable is 1 less. How do I create meaningful cell name like k{0}?
Also, say I have an array A. There are also some times i need meaningful variable name, such as
c111 = A(1)*A(1)*A(1)
c222 = A(2)*A(2)*A(2)
c333 = A(3)*A(3)*A(3)
How can I create c{111} efficiently using for loop?
Use structures:
D = rand(21);
c = 1;
for k = -10:10
if k<0
s.(['k_' num2str(abs(k))]) = D(c,c);
else
s.(['k' num2str(k)]) = D(c,c);
end
c = c+1;
end
This will give you a structure like:
s =
k_10: 0.51785
k_9: 0.90121
k_8: 0.40746
k_7: 0.092989
.
.
k_1: 0.75522
k0: 0.55257
k1: 0.28708
.
.
k9: 0.94182
k10: 0.2124
and don't use eval...
Answer to 1st Question:-
D=randn(100); % A matrix of random elements of size 8x8
for m=0:99
assignin('base', ['k' num2str(m)], D(m+1,m+1))
end
Answer to 2nd Question:-
A=randn(1,3); % An array of 3 random elements
for n=1:3
assignin('base', ['c' num2str(111*n)], A(n)^3)
end
Comments:-
You've stated that you need variables like k0,k1,k2,... and c111,c222,c333 but you're asking how to create k{0}, k{1},k{2},... and c{111},c{222},c{333}. As far as your need is concerned, I have given answer to it. Regarding the latter, k{0} is never possible and c{111},c{222},c{333},... don't make good sense without using any of the first 0:100 values and then 112:221 values and so on. Although you can do it using:
A=rand(1,3); % An array of 3 random elements
c{333} = 0 ; % Pre-allocation
for p=1:3 % Since you want to use a 'for loop'
c{111*p} = A(p)^3;
end
And regarding the requirement that you made in the comment in these words "I also have some variable using negative index", you can never have variables in the negative index. If you mean you want to create variables with names like k-1, k-2,... etc, it is not possible. An alternate way is to use k_1, k_2,... etc but then as you said in the question "k0 refers to D(1,1), i.e. the number in my variable is 1 less". It means k_1 will refer to D(0,0) and so on which is again an invalid thing for MATLAB.
Recommendation:-
You really need to modify your code.

How to convert cell variable to classified variable inside of parfor loop in matlab? [duplicate]

I have this (quite long) Matlab code with nested loops where I want to parallelize the main time-consuming iteration. The only variable that (apparently) gives me problems is DMax, where I get the error:
Error: The variable DMax in a `parfor` cannot be classified.
See Parallel for Loops in MATLAB, "Overview".
This is a draft of my code:
t0=matrix (Maxiter,1); % This is a big matrix whose dimensions are reported in brachets
Maxiter = 1E6;
DMax = zeros(Maxiter,40);
% Other Stuff
for j=1:269
% Do more stuff
for soil=1:4
parfor i =1:Maxiter
k(i,soil) = a %k is a real number
a(i,soil) = b %similar to k
% Do a lot of stuff
for t= (floor(t0(i,soil))+1):40
DMax(i,t) = k(i,soil)*((t-t0(i,soil))^a(i,soil));
% Do some more stuff
end
end
end
end
for time=1:40
% Do the final stuff
end
I guess the problem is in the way I defined DMax, but I do not know what it could be more precisely. I already looked on the web but with not very satisfying results.
It is very clearly described in the documentation that each variable inside parfor must be classified into one of several types. Your DMax variable should be a sliced variable (arrays whose segments are operated on by different iterations of the loop), but in order to be classified as such, all the following conditions must hold:
Type of First-Level Indexing — The first level of indexing is either parentheses, (), or braces, {}.
Fixed Index Listing — Within the first-level parenthesis or braces, the list of indices is the same for all occurrences of a
given variable.
Form of Indexing — Within the list of indices for the variable, exactly one index involves the loop variable.
Shape of Array — The array maintains a constant shape. In assigning to a sliced variable, the right-hand side of the assignment cannot be [] or '', because these operators attempt to
delete elements.
Clearly, Fixed Index Listing property does not hold since you reference it as DMax(i,t) where t changes its values. There's an identical example described in the documentation, please pay attention. So one workaround would be to use a temporary variable inside the inner loop, and then assign the whole row back to DMax.
Also note that variable a cannot be classified into any category either. That's not to mention that it's not defined in your example at all. Please read the guide carefully and make sure it can be classified into one of the categories. Rewrite the code if needed, e.g. introducing new temporary variables.
Here's the code where DMax usage is corrected:
Maxiter = 1E6;
t0 = randn(Maxiter,1); % This is a big matrix whose dimensions are reported in brachets
DMax = zeros(Maxiter,40);
% Other Stuff
for j = 1:269
% Do more stuff
for soil = 1:4
parfor i = 1:Maxiter
k(i,soil) = a %k is a real number
a(i,soil) = b %similar to k
% Do a lot of stuff
tmp = zeros(1,40);
for t = (floor(t0(i,soil))+1):40
tmp(t) = k(i,soil)*((t-t0(i,soil))^a(i,soil));
% Do some more stuff
end
DMax(i,:) = tmp;
end
end
end
for time = 1:40
% Do the final stuff
end

In an assignment A(I) = B, the number of elements in B and I must be the same

This is my code in Matlab: How could I get all values of all 5 images saved? This code only returns the last image! I tried using IM(l) but it gives me an error: In an assignment A(I) = B, the number of elements in B and I must be the same.
Amount_measurements = 5;
IM=zeros(2097152,1);
l=1;
for l=(1:Amount_measurements)
if l < 9
%index = double(0)+double(0)+double(l+1);
index = strcat(num2str(double(0)),num2str(double(0)),num2str(double(l+1)));
elseif l < 99
index = double(0)+double(l+1);
else
index = double(l+1);
end
file_name1='trial.nii.gz';
%disp(file_name1);
jesu=load_nii(file_name1);
[x,y,z] = meshgrid(1:256,1:256,1:256);
[lx,ly,lz] = meshgrid(1:2:256,1:2:256,1:2:256);
newImage = interp3(x,y,z,jesu.img,lx,ly,lz);
IM= newImage(:);
end
I want the values newImage(:) to be stored as IM1=newImage(:) IM2=newImage(:) IM3=newImage(:) IM4=newImage(:) so on... How could I go about with it?
Since you mentioned wanting a variable-length version of IM1=newImage(:) IM2=newImage(:) IM3=newImage(:) IM4=newImage(:), you're looking for a cell array. Try
IM{l} = newImage;
instead of
IM(l) = newImage(:);
The important difference is the use of braces rather than parentheses. Use a right-hand side ofnewImage(:) if you want to reshape into a vector, just newImage if you want to preserve it as a matrix.
By using IM(l) you're trying to add an entire column vector (newImage(:)) to a single element (the l-th element) in the array IM, that's why Matlab throws the error.
You should consider concatenation: since newImage(:) is a column-vector, replace
IM= newImage(:);
with
IM=[IM newImage(:)];
but at the top of the script you should also initialize IM as
IM=[];
At the end of the loop, the resulting IM will have Amount_measurements columns where 1 column = 1 newImage(:).
Note #1: this will only work if newImage(:) always has the same length.
Note #2: if you know a priori how long the vector newImage(:) is and, again, by assuming that its length never changes, you should consider preallocating the IM matrix by replacing IM=[]; with IM=zeros(X,Amount_measurements); where X is the number of elements in newImage(:). Finally, regarding the concatenation stage, you should replace IM=[IM newImage(:)]; with IM(:,l)=newImage(:).
Note #3: as instead, if the size of newImage(:) can change you cannot rely on preallocation and matrices, but you must use cell arrays: the last instruction in your loop should be IM{l}=newImage(:);.

Using loops to get multiple values into a cell

I have 31 subjects (S1, S2, S3, S4, etc.). Each subject has 3 images, contrast1.img, contrast2.img, and contrast3.img. I would like to use a loop to get all paths to the contrasts from all the subjects into a nx1 cell called P. P should be something like this:
Data/S1/contrast1.img
Data/S1/contrast2.img
Data/S1/contrast3.img
Data/S2/contrast1.img
Data/S2/contrast2.img
Data/S2/contrast3.img
...
Data/S31/contast3.img
This is what I've tried:
A={'S1','S2','S3',...,'S31'}; % all the subjects
C={'contrast1.img','contrast2.img','contrast3.img'}; % contrast images needed for each subject
P=cell(31*3,1)
for i=1:length(A)
for j=1:length(C)
P{j}=spm_select('FPList', fullfile(data_path, Q{i}) sprintf('%s',cell2mat(C(j)))); % this is to select the three contrast images for each subject. It works in my script. It might not be 100% correct here since I had to simplify for this example.
end
end
This, however, only give me P with the 3 contrast images of the last subject. Previous subjects get overwritten. This indicates that the loop is wrong but I'm not sure how to fix it. Could anyone help?
No loop needed. Use ndgrid to generate the combinations of numbers, num2str with left alignment to convert to strings, and strcat to concatenate without trailing spaces:
M = 31;
N = 3;
[jj ii] = ndgrid(1:N, 1:M);
P = strcat('Data/S',num2str(ii(:),'%-i'),'/contrast',num2str(jj(:),'%-i'),'.img')
I would use a cell matrix, which directly represents the subject index and the contrast index.
To preallocate use P=cell(length(A),length(C)) and to fill it use P{i,j}=...
When you want to access the 3rd image of the 5th subject, use P{5,3}
The problem is where you assign P{j}.
Since j only loops 1:3 and doesn't care about i, you are just rewriting all three values for P{j}. I think you want to concatenate the new values to the cell array instead
for i=1:length(A)
for j=1:length(C)
P ={P; spm_select('FPList', fullfile(data_path, Q{i}) sprintf('%s',cell2mat(C(j))));}
end
end
or you could assign each value directly such as
for i=1:length(A)
for j=1:length(C)
P{3*(i-1)+j} =spm_select('FPList', fullfile(data_path, Q{i}) sprintf('%s',cell2mat(C(j))));
end
end

Mark values from loop for each iteration

I want to mark each value that comes out of my loop with a value.
Say I have a variable number of values that come out of each iteration. I want those values to be labeled by which iteration they came out of.
like
1-1,
2-1,
3-1,
1-2,
2-2,
3-2,
4-2,
etc.
where the first number is the value from the loop and the second is counting which iteration it came from.
I feel like there is a way I just cant find it.
ok so here is some code.
for c=1:1:npoints;
for i=1:1:NN;
if ((c-1)*spacepoints)<=PL(i+1) && ((c-1)*spacepoints)>=PL(i);
local(c)=((c)*spacepoints)-PL(i);
end
if ((c-1)*spacepoints)>=PL(NN);
local(c)=((c)*spacepoints)-PL(NN);
element(i)=NN;
end
end
I want to mark each local value with the iteration it came from for the i:NN. PL is a vector and the output is a set of vectors for each iteration.
For this sort of quick problem I like to create a cell array:
for k = 1:12
results{k} = complicated_function(...);
end
If the output is really complicated, then I return a struct with fields relating to the outputs:
for k = 1:12
results{k}.file = get_filename(...);
results{k}.result = ...;
end
Currently as it is right now, in your inner 1:NN loop, your local(c) variable is being updated or overwritten. You never apply the previous value of local, so it is not some iterative optimization algorithm(?)...
Perhaps an easy solution is to change the size/type of local from a vector to a matrix. Let's say that local is of size [npoints 1]. Instead you make it of size [npoints NN]. It is now a 2d-array (a matrix of npoints rows and NN columns). use the second dimension to store each (assumed column) vector from the inner loop:
local = zeros([npoints NN]);
%# ... code in bewteen ...
for c=1:1:npoints;
for i=1:1:NN;
if ((c-1)*spacepoints)<=PL(i+1) && ((c-1)*spacepoints)>=PL(i);
local(c, i)=((c)*spacepoints)-PL(i);
end
if ((c-1)*spacepoints)>=PL(NN);
local(c, i)=((c)*spacepoints)-PL(NN);
element(i)=NN;
end
end
end
The c'th row of your local matrix will then corresponds to the NN values from the inner loop. Please note that I have assumed your vector to be a column vector - if not, just change the order of the sizes.