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].
Related
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
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.
I'm trying to find the index position of the smaller vector inside a bigger one.
I've already solved this problem using strfind and bind2dec,
but I don't want to use strfind, I don't want to convert to string or to deciamls at all.
Given the longer vector
a=[1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,0,0,1,1];
I want to find the index of the smaller vector b inside a
b=[1,1,1,0,0,0];
I would expect to find as result:
result=[15,16,17,18,19,20];
Thank you
Here is as solution using 1D convolution. It may find multiple matches so start holds beginning indices of sub-vectors:
f = flip(b);
idx = conv(a,f,'same')==sum(b) & conv(~a,~f,'same')==sum(~b);
start = find(idx)-ceil(length(b)/2)+1;
result = start(1):start(1)+length(b)-1;
Solution with for loops:
a=[1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,0,0,1,1];
b=[1,1,1,0,0,0];
c = [];
b_len = length(b)
maxind0 = length(a) - b_len + 1 %no need to search higher indexes
for i=1:maxind0
found = 0;
for j=1:b_len
if a(i+j-1) == b(j)
found = found + 1;
else
break;
end
end
if found == b_len % if sequence is found fill c with indexes
for j=1:b_len
c(j)= i+j-1;
end
break
end
end
c %display c
Does it need to be computationally efficient?
A not very efficient but short solution would be this:
a=[1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,0,0,1,1];;
b=[1,1,1,0,0,0];
where = find(arrayfun(#(n) all(a(n+1:n+length(b))==b),0:length(a)-length(b)));
... gives you 15. Your result would be the vector where:where+length(b)-1.
edit: I tried it and I stand corrected. Here is a version with loops:
function where = find_sequence(a,b)
na = 0;
where = [];
while na < length(a)-length(b)
c = false;
for nb = 1:length(b)
if a(na+nb)~=b(nb)
na = na + 1; % + nb
c = true;
break
end
end
if ~c
where = [where,na+1];
na = na + 1;
end
end
Despite its loops and their bad reputation in Matlab, it's a lot faster:
a = round(rand(1e6,1));
b = round(rand(10,1));
tic;where1 = find(arrayfun(#(n) all(a(n+1:n+length(b))==b),0:length(a)-length(b)));toc;
tic;where2 = find_sequence(a,b);toc;
>> test_find_sequence
Elapsed time is 4.419223 seconds.
Elapsed time is 0.042969 seconds.
A neater method using for would look like this, there is no need for an inner checking loop as we can vectorize that with all...
a = [1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,0,0,1,1];
b = [1,1,1,0,0,0];
idx = NaN( size(b) ); % Output NaNs if not found
nb = numel( b ); % Store this for re-use
for ii = 1:numel(a)-nb+1
if all( a(ii:ii+nb-1) == b )
% If matched, update the index and exit the loop
idx = ii:ii+nb-1;
break
end
end
Output:
idx = [15,16,17,18,19,20]
Note, I find this a bit easier to read that some of the nested solutions, but it's not necessarily faster, since the comparison is done on all elements in b each time.
I apologize in advance, I'm sure the answer to this question is quite trivial, unfortunately I am just not sure what is going on.
I am trying to run the following code
a(1) = -2;
b(1) = 2;
c(1) = 0;
for i = 1:15
if cubicPoly(a(i))*cubicPoly(c(i)) < 0
a(i+1) = a(i);
b(i+1) = c(i);
else
a(i+1) = c(i);
b(i+1) = b(i);
end
end
but when I do I receive the error message
Index exceeds matrix dimensions.
Error in Assignment2 (line 31)
if cubicPoly(a(i))*cubicPoly(c(i)) < 0
If I evaluate my cubic polynomial function cubicPoly normally, everything works just fine. But inside the for/if loop when evaluated at the sequences a(i) and c(i) it results in an error.
Any help would be appreciated.
It doesn't look like you ever add more elements to c; when i = 2, you're trying to access c(2) in if cubicPoly(a(i))*cubicPoly(c(i)) < 0, which takes you out of bounds.
You might want to include something like c(i+1) = ... if you intend to add elements to c while looping.
Is it possible to obtain the matrix A in a more efficient way than using a for loop?
a = 6; % constant
b = 2; % constant
s = 0.1; % possible to change
I = 12; % possible to change
A = zeros(a,I+1);
A(:,1) = rand(a,1); % some initial value
B = rand(b,I);
% possible to avoid for-loop to increase performance?
for i = 1:I
A(:,i+1) = fun(A(:,i),B(:,i), a, s);
end
The function fun is given as
function [AOut] = fun(AIn, B, a, s)
AOut = zeros(a,1);
AOut(1) = AIn(1) + AIn(4)*s*cos(AIn(3));
AOut(2) = AIn(2) + AIn(4)*s*sin(AIn(3));
AOut(3) = AIn(3) + AIn(4)*AIn(6)*s;
AOut(4) = AIn(4) + AIn(5)*s;
AOut(5) = AIn(5) + B(1);
AOut(6) = AIn(6) + B(2);
end
i dont think you can optimize the loop in regards to effiency as the last values are needed for calculating the next. #Tony Tannous showed you a nice way how to get rid of the loop in your code. For better performance at high values of I you can change fun() to:
function [AOut] = fun2(AIn, B, a, s)
AOut=AIn+ [AIn(4)*s*cos(AIn(3)) ;...
AIn(4)*s*sin(AIn(3)) ;...
AIn(4)*AIn(6)*s ;...
AIn(5)*s ; ...
B(1) ; ...
B(2)];
end
First of all, if a != n
You will get an error:
Subscripted assignment dimension mismatch.
So you must be cautious
And, to get rid of the loop you can do this:
EDIT:
Apparently i isn't getting modified on the right side. I'll try to fix it and reedit my answer.
anyway, to get rid of the loop you can still use A(:, i:1:I)
i = 1;
A(:, i:1:I) = fun(A(:,i),B(:,i), a, s);
If you have any further question, please ask!