creating a loop to convert elements of a matrix in matlab - matlab

Question: Create a copy of check called checkflip. Then, create a loop that converts each element of checkflip to 1 if its value is 0 and to 0 if its value is 1. The code within your loop should operate on only one element of checkflip at a time
In previous questions, I established check in the code below:
x=[0 1];
y=x([2 1]);
check=repmat([repmat(y,1,4);repmat(x,1,4)], 4, 1);
I've tried the code below to solve my question but it doesn't seem to do anything and i am not sure why
checkflip=check;
x=checkflip;
for i=1:8
if x(i)==0
x(i)=1;
elseif x(i)==1
x(i)=0;
end
end

Taking the complement using ~ is an option to flip each value in the matrix using a set of for-loops. A set of two for-loops can be used to traverse through each index of the array 1 by 1. The outer for-loop controls the scanning through the rows and the inner for-loop controls scanning through the columns. Alternatively, method 3 shows how to use a single loop and evaluate the corresponding row (i) and column (j) accordingly. It's important to be careful with consecutive if statement because sometimes within the first if statement's body checkflip can be flipped causing the second if statement to trigger accidentally. Sometimes it can be good practice not to involve the same variables in consecutive if statements and their bodies.
Edit: Alternatively you can use one for-loop that runs from 1 to the number of array elements in this case 64 since MATLAB index arrays by traversing the rows from left to right.
Looping Methodology:
Below shows the looping method for a 5 by 5 array/matrix but this can easily be extended to arrays/matrices of any size.
Method 1: Using Complement
x=[0 1];
y=x([2 1]);
check = repmat([repmat(y,1,4);repmat(x,1,4)], 4, 1);
checkflip = check;
for i = 1: 8
for j = 1: 8
checkflip(i,j) = ~checkflip(i,j);
end
end
or
x=[0 1];
y=x([2 1]);
check = repmat([repmat(y,1,4);repmat(x,1,4)], 4, 1);
checkflip = check;
for i = 1: 64
checkflip(i) = ~checkflip(i);
end
Method 2: Using If Statements
x=[0 1];
y=x([2 1]);
check = repmat([repmat(y,1,4);repmat(x,1,4)], 4, 1);
checkflip = check;
for i = 1: 8
for j = 1: 8
if(checkflip(i,j) == 0)
Result = 1;
end
if(checkflip(i,j) == 1)
Result = 0;
end
checkflip(i,j) = Result;
end
end
Method 3: Limited to One Loop
x=[0 1];
y=x([2 1]);
check = repmat([repmat(y,1,4);repmat(x,1,4)], 4, 1);
checkflip = check;
i = 1;
j = 0;
for Loop = 1: 64
j = j + 1;
if(j > 8)
j = 1;
i = i + 1;
end
if(checkflip(i,j) == 0)
Result = 1;
end
if(checkflip(i,j) == 1)
Result = 0;
end
checkflip(i,j) = Result;
end
Edit: A great solution suggested by #David uses the function numel() to transverse over all the array elements seamlessly:
x=[0 1];
y=x([2 1]);
check = repmat([repmat(y,1,4);repmat(x,1,4)], 4, 1);
checkflip = check;
for i=1:numel(checkflip)
checkflip(i) = ~checkflip(i);
end
Extension: Without a Loop (excepted from the question, all elements at once)
x=[0 1];
y=x([2 1]);
check = repmat([repmat(y,1,4);repmat(x,1,4)], 4, 1);
checkflip = double(~check);
Ran using MATLAB R2019b

Related

Output 1, 0.5, or 0 depending if a matrix elements are prime, 1, or neither

I am sending a matrix to my function modifikuj, where I want to replace the elements of the matrix with:
1 if element is a prime number
0 if element is a composite number
0.5 if element is 1
I dont understand why it is not working. I just started with MATLAB, and I created this function:
function B = modifikuj(A)
[n,m] = size(A);
for i = 1:n
for j = 1:m
prost=1;
if (A(i,j) == 1)
A(i,j) = 0.5;
else
for k = 2:(A(i,j))
if(mod(A(i,j),k) == 0)
prost=0;
end
end
if(prost==1)
A(i,j)=1;
else
A(i,j)=0;
end
end
end
end
With
A = [1,2;3,4];
D = modifikuj(A);
D should be:
D=[0.5, 1; 1 0];
In MATLAB you'll find you can often avoid loops, and there's plenty of built in functions to ease your path. Unless this is a coding exercise where you have to use a prescribed method, I'd do the following one-liner to get your desired result:
D = isprime( A ) + 0.5*( A == 1 );
This relies on two simple tests:
isprime( A ) % 1 if prime, 0 if not prime
A == 1 % 1 if == 1, 0 otherwise
Multiplying the 2nd test by 0.5 gives your desired condition for when the value is 1, since it will also return 0 for the isprime test.
You are not returning anything from the function. The return value is supposed to be 'B' according to your code but this is not set. Change it to A.
You are looping k until A(i,j) which is always divisible by itself, loop to A(i,j)-1
With the code below I get [0.5,1;1,0].
function A = modifikuj(A)
[n,m] = size(A);
for i = 1:n
for j = 1:m
prost=1;
if (A(i,j) == 1)
A(i,j) = 0.5;
else
for k = 2:(A(i,j)-1)
if(mod(A(i,j),k) == 0)
prost=0;
end
end
if(prost==1)
A(i,j)=1;
else
A(i,j)=0;
end
end
end
end
In addition to #EuanSmith's answer. You can also use the in built matlab function in order to determine if a number is prime or not.
The following code will give you the desired output:
A = [1,2;3,4];
A(A==1) = 0.5; %replace 1 number with 0.5
A(isprime(A)) = 1; %replace prime number with 1
A(~ismember(A,[0.5,1])) = 0; %replace composite number with 0
I've made the assumption that the matrice contains only integer.
If you only want to learn, you can also preserve the for loop with some improvement since the function mod can take more than 1 divisor as input:
function A = modifikuj(A)
[n,m] = size(A);
for i = 1:n
for j = 1:m
k = A(i,j);
if (k == 1)
A(i,j) = 0.5;
else
if all(mod(k,2:k-1)) %check each modulo at the same time.
A(i,j)=1;
else
A(i,j)=0;
end
end
end
end
And you can still improve the prime detection:
2 is the only even number to test.
number bigger than A(i,j)/2 are useless
so instead of all(mod(k,2:k-1)) you can use all(mod(k,[2,3:2:k/2]))
Note also that the function isprime is a way more efficient primality test since it use the probabilistic Miller-Rabin algorithme.

Setting Table Values using Loops with Index Vectors in Matlab

I've a series of coordinates (i,j) and I want to loop through each one.
For example
A = ones(3,3);
i = [1 2 3];
j = [3 2 1];
I tried with this but it doesn't work:
for (i = i && j = j)
A(i,j) = 0;
end
I also tried this but it doens't work as expected:
for i = i
for j = j
A(i,j) = 0;
end
end
Desired result:
A =
1 1 0
1 0 1
0 1 1
Although A is a matrix in this example, I am working with table data.
The correct syntax to do what you want is:
A = ones(3,3);
i = [1 2 3];
j = [3 2 1];
for ii = 1:length( i )
A( i(ii) , j(ii) ) = 0;
end
Essentially you loop through each element and index i and j accordingly using ii. ii loops through 1..3 indexing each element.
This will give the a final result below.
>> A
A =
1 1 0
1 0 1
0 1 1
While this works and fixes your issue, I would recommend rayryeng's alternate solution with conversions if you don't have more complex operations involved.
Though this doesn't answer your question about for loops, I would avoid using loops all together and create column-major linear indices to access into your matrix. Use sub2ind to help facilitate that. sub2ind takes in the size of the matrix in question, the row locations and column locations. The output will be an array of values that specify the column-major locations to access in your matrix.
Therefore:
A = ones(3); i = [1 2 3]; j = [3 2 1]; %// Your code
%// New code
ind = sub2ind(size(A), i, j);
A(ind) = 0;
Given that you have a table, you can perhaps convert the table into an array, apply sub2ind on this array then convert the result back to a table when you're done. table2array and array2table are useful tools here. Given that your table is stored in A, you can try:
Atemp = table2array(A);
ind = sub2ind(size(Atemp), i, j);
Atemp(ind) = 0;
A = array2table(Atemp);

MATLAB - How to create output for each iteration of a looped calculation

This calculation aims to take a value (a) and perform one of two calculations on it for each iteration of a loop. Each sequential loop takes the new calculated value and recalculates it. I would like to keep the outputted value from each loop. Here is an example, using a logical array to decide which calculation to use over each of the 5 loops:
a = 0;
b = logical([1 0 1 1 0]);
for i = 1:length(b)
if b(i) == 1
a = 1*2 + a*2
else
a = a*3
end
end
This example is not correct as it only returns 1 value for a rather than 5. The desired result from this example is:
a = 2 6 14 30 90
Please help me and amend anything else that is wrong here. Many thanks.
You can do
a = [0];
b = logical([1 0 1 1 0]);
for i = 1:length(b)
if b(i) == 1
a(end+1) = 1*2 + a(end)*2;
else
a(end+1) = a(end)*3;
end
end

Extremely strange for loop behavior in Matlab

When attempting to write a for loop to increment from 1 to the end of an array, Matlab throws an error saying that I attempted to access the 0th array element, which doesn't exist. Here's the snippet in question:
function [adjMatNew] = delete(obj, adjMat)
[~, n] = size(adjMat);
adjMatNew = adjMat;
for i = 1:n
if adjMat(obj.number, i) ~= 0
adjList(i) = i
end
end
for j = 1:numel(adjList)
for k = 1:numel(adjList)
if j ~= k
adjMatNew(adjList(k), adjList(j)) = 1;
end
end
end
adjMatNew(obj.number, :) = 0;
adjMatNew(:, obj.number) = 0;
end
I can't think of any possible reason why, in the for loops above, the loop would start at 0. Changing the beginning increment variable from 1 to 2 fixed the issue and the function worked as intended, but it doesn't seem like the right fix. Does anybody have an explanation for this?
Without any help or comments, it's not very clear what you're actually attempting to do; however, in the line
adjMatNew(adjList(k), adjList(j)) = 1;
you implicitly assume that adjList is never zero. Since that is apparently the case, you get the error.
As suggested in other comments/answers, the issue is where you construct adjList.
for i = 1:n
if adjMat(obj.number, i) ~= 0
adjList(i) = i
end
end
Let's consider what happens in three different situations where n = 3:
1) If all of adjMat(obj.number, 1:3) are ~=0, each loop
adjList(1) = 1;
adjList(2) = 2;
adjList(3) = 3;
output: adjList = [1,2,3];
This case shouldn't throw an error.
2) If adjMat(obj.number, 3) is zero:
adjList(1) = 1;
adjList(2) = 2;
% adjList(3) not set
output: adjList = [1,2];
No error here, either.
3) If adjMat(obj.number, 2) is zero:
adjList(1) = 1;
% adjList(2) not set
adjList(3) = 3;
Since adjList(2) is not set, when calling adjList(3) = 3;, MATLAB needs there to be some value for adjList(2). By default, this is handled by filling with zeros to make the matrix the right size:
output: adjList = [1 0 3];
This causes the error.
As suggested in the comments by Notlikethat, adjList = find(adjMat(obj.number,:)) would be good way of replacing this loop. In this case, it only returns the positions of the non zero elements, so in the third case above, the output would be adjList = [1 3].

Raplacing for loop by a single line statement in MATLAB

I have this function which needs to be run hundreds of times. It contains a for loop which I am trying to remove to make the function faster. Can someone help me replace the loop by a single line command.
nn = 4;
T = [5 1 2; 5 2 3; 5 3 4; 5 4 1];
p = [0 0; 1 0; 1 1; 0 1; 0.5 0.5];
A = zeros(nn,1);
for i=1:nn
sctr = T(i,:); pT = p(sctr,:);
A(i) = 1/2*det([pT,ones(3,1)]);
end
Perhaps removing det and replacing it with actual formula to calculate the determinant will help?
The For loop solution you have is probably the fastest. Other options are:
B = [p(T',:),ones(3*size(T,1),1)]
C= mat2cell(B,[3,3,3,3],3)
D= cellfun(#det,C);
or also you can write instead of D this expression
D = arrayfun(#(x) det(C{x}), 1 : size(C, 1));
etc...
I think this would work (I couldn't test it since I don't have my environment with me)
pT = p(T(1:nn,:),:);
A = 1/2 * det([pT, ones(3, 1)]);
You can obviously do a one line code from the code above but this would be less readable.
If it doesn't work and you keep the for-loop, at least consider the matrix preallocation (for A, pT and sctr) this will speed up your program.