Matrix 'if' statement

263 views (last 30 days)
Eva Carrillo on 2 Dec 2019
Edited: Manuel Dullnig on 31 Aug 2021
I just learned how to do matrices today, and am quite confused on this problem. So I have to create a 100 x 100 matrix. Every spot in the matrix takes on the value , where i represents the row and j represents the column location. I have a formula in which the value K is defined as the greater value of i and j. I need to create an if loop that compares the row and column position values and chooses the larger of the two, then defines that as the variable K.
I don't know what kind of syntax to use in terms of matrices. I know how to build an if staement, but am jsut simply confused on the kind of matlab syntax that needs to be followed.
Manuel Dullnig on 24 Aug 2021
KALYAN you said one can do it without a loop. I need to do this without the loop, can you show me how?

John D'Errico on 24 Aug 2021
Edited: John D'Errico on 24 Aug 2021
One thing that new users of MATLAB mistake, is they want an if statement to apply to every element of a matrix or vector. For example:
M = magic(7)
M = 7×7
30 39 48 1 10 19 28 38 47 7 9 18 27 29 46 6 8 17 26 35 37 5 14 16 25 34 36 45 13 15 24 33 42 44 4 21 23 32 41 43 3 12 22 31 40 49 2 11 20
So M is a matrix. Now users want to have an if statement that will do something different for every element of the matrix, depending on some test, and MATLAB does not have such an ability, at least not as they want. But there are some things you can do. For example, suppose I wanted to divide all of the even numbers by 2, but for the odd numbers, I want to multiply by 3, and then add 1? (You may recognize what I am doing here, if not, then you could do some reading about the Collatz conjecture, sometimes just called the 3n+1 problem.)
Solution 1: Just use a loop.
for i = 1:numel(M)
if rem(M(i),2) == 0
M(i) = M(i)/2; % even condition
else
M(i) = 3*M(i) + 1; % odd condition
end
end
M
M = 7×7
15 118 24 4 5 58 14 19 142 22 28 9 82 88 23 3 4 52 13 106 112 16 7 8 76 17 18 136 40 46 12 100 21 22 2 64 70 16 124 130 10 6 11 94 20 148 1 34 10
So it did exactly as we need it to do, operating on each element of M separately. Note that the loop uses a linear index, treating the matrix as if it were a vector of elements. This works in MATLAB, so I did not need to create a double loop on the rows AND the columns of M.
But the MATLAB way is to use matrices. That is how MATLAB is really written to be efficient. So we might have used this next idea. (I'll just apply it directly to the last result of M.)
Solution 2:
% create a boolean variable that is either 0 or 1, depending on whether the
% corresponding element in M was even or odd.
evenloc = rem(M,2) == 0;
oddloc = ~evenloc;
M(evenloc) = M(evenloc)/2;
M(oddloc) = 3*M(oddloc) + 1;
M
M = 7×7
46 59 12 2 16 29 7 58 71 11 14 28 41 44 70 10 2 26 40 53 56 8 22 4 38 52 9 68 20 23 6 50 64 11 1 32 35 8 62 65 5 3 34 47 10 74 4 17 5
As you can see, this also worked. No explicit loops were used, although internally inside the guts of MATLAB, it will be performing a loop in a lower level language, so an implicit loop. It employed what is called a boolean index. I could also have used find in a very similar way.
Solution 3:
% create a list of the elements in M that were even,
% and another list of the odd elements.
evenloc = find(rem(M,2) == 0);
oddloc = find(rem(M,2) == 1);
% Use those lists to index into M.
M(evenloc) = M(evenloc)/2;
M(oddloc) = 3*M(oddloc) + 1;
M
M = 7×7
23 178 6 1 8 88 22 29 214 34 7 14 124 22 35 5 1 13 20 160 28 4 11 2 19 26 28 34 10 70 3 25 32 34 4 16 106 4 31 196 16 10 17 142 5 37 2 52 16
These are the common solutions you may see. Certainly there are others ways to do it too. I might have tried to be tricky, perhaps like this:
Solution 4:
mfac = [1/2 3];
afac = [0 1];
M = mfac(rem(M,2) + 1) .* M + afac(rem(M,2) + 1)
M = 7×7
70 89 3 4 4 44 11 88 107 17 22 7 62 11 106 16 4 40 10 80 14 2 34 1 58 13 14 17 5 35 10 76 16 17 2 8 53 2 94 98 8 5 52 71 16 112 1 26 8
You may wish to look carefully at this last one. Why did it work? (Because it does work.) We could even use the last idea to usein a simple iteration scheme to play with the classic Collatz problem.
mfac = [1/2 3];
afac = [0 1];
% creating a simple function handle to perform one step of the Collatz
% iteration.
Miter = @(M) mfac(rem(M,2) + 1) .* M + afac(rem(M,2) + 1);
niter = 0;
while any(~ismember(M(:),[1 2 4]))
niter = niter + 1;
M = Miter(M);
end
niter
niter = 105
% and so, after 105 more iterations, we see that every element has now
% stabilized into the 3 oscillating terminal elements in the famous
% Collatz conjecture.
M
M = 7×7
4 1 2 4 4 2 4 4 2 1 1 2 4 4 1 2 4 4 1 1 4 2 2 1 2 1 4 1 4 2 1 2 2 1 2 1 4 2 1 2 1 4 4 1 2 4 1 2 1
And there are cetainly other creative ways to solve the problem. In any such scheme I should have probably worried if the number was too large to be exactly representable as an integer in floating point arithematic in MATLAB, thus as a double. The limit for that is calling flintmax in MATLAB, but now I am digressing too far.
Manuel Dullnig on 31 Aug 2021
thank you so much for taking the time!

Wan Ji on 24 Aug 2021
If you do not want the loop, then
M = 100; N = 100;
[j, i] = meshgrid(1:N,1:M);
q = i>j;
A(q) = i(q);
A(~q)=j(~q);
Wan Ji on 24 Aug 2021
Hi, Jan
Thank you very much for your comment.
You open a door of new world in matlab for me. How surprising to see its simple and beautiful.
Wan Ji