Function output contradicts function constraints - matlab

I wrote a function that takes as an imput a natural number 'n', and outputs a random walk, starting at 0, where each subsequent entry in the vector is obtained by adding or subtracting 1 to the previous entry. The random walk has to stop whenever it reaches n or -n.
The code is the following
function [N] = rand_walk2(n)
j=0; %J will be the outpur of the function
v=0; %Defines variable v.
i=2; %The following 'while' loop will start from the second entry of the vector.
while abs(j(i-1)) < n %This 'while' loop will continue running only if the previous entry is strictly between -n and n.
if rand >= 0.5 %This 'if' statement returns 1 or -1 with equal probability (it uses the uniform distribution with parameters [0,1]).
v = 1;
else v = -1;
end
j(i)=j(i-1)+v;
j = [j,j(i)];
i=i+1;
end
N = j;
end
The problem is that the output returns n or -n twice instead of only once, for example, if I evaluate rand_walk2(3) I get 0 -1 -2 -3 -3 instead of just o -1 -2 -3. Does anyone have any suggestions as to what I can change to fix this?

Line 10 pushes the current position into vector j
j(i)=j(i-1)+v;
and then line 11 concatenates that same value on to the end of the array
j = [j,j(i)];
Simply remove line 11.
As a usual side note, the symbols i and j are often used to produce imaginary numbers and often mistakenly as indexing variables. It is recommended by Mathworks:
Since i is a function, it can be overridden and used as a variable. However, it is best to avoid using i and j for variable names if you intend to use them in complex arithmetic.
In this case, it is not necessary, but I like to promote good programming practices when I can (also, I needed to force my brain to think through your code because of this practice).

Related

MATLAB - Check matrix to see if two consecutive numbers = 0

I have a matrix being created in MATLAB but need to check if any two consecutive numbers (by row) = 0 and if it does output with a yes or no without showing the answers. Ive put my code below my final loop is returning errors and im not too sure how to go about this.
%%Input positive integer
n=input('Give a positive integer greater than 1: ');
%%Error for below 1
if n<=1
error('The value given is less than or equal to 1')
end
%%loop for vector v
for i=1:n
v(i)=2^i*3;
end
%display vector
v
A=randi([-5,5],n,n);
A
x = 1;
consecutive = false;
for i = 1:25
if (A(x) + A(x+1) = 0);
consecutive = true;
end
end
There's a lot wrong with the code of your final loop:
You set x to 1 and use it as an index into A, but never change it from 1.
As Amit points out, you are using = (used for assignment) when you should be using == (the equality operator).
As Gondrian points out, you are testing if a sum is equal to zero, but from your description it sounds like you should be testing if each value is zero.
Your loop iterates 25 times (i = 1:25), but it's not clear why, since your matrix A is of size n-by-n.
Instead of using a for loop, it's possible to do this with indexing instead. Since you are checking for consecutive zeroes by row, this is what it would look like:
zeroPairs = (A(:, 1:(n-1)) == 0) & (A(:, 2:n) == 0);
consecutive = any(zeroPairs(:));
The term A(:, 1:(n-1)) gets all of the "left" values in each pairwise comparison and the term A(:, 2:n) gets all of the "right" value. These are compared to 0, then combined. This creates an n-by-(n-1) matrix zeroPairs where a value of true indicates where a pair of consecutive zeroes occurs. This matrix is reshaped into a column vector and any is used to check if a value of true is present anywhere.
You will need to change your if block as follows.
if (A(x) + A(x+1) == 0);
consecutive = true;
end
Notice the == instead of just =. The first one is for comparison and the second one is for assignment. This will get rid of the error that you are currently getting. There may be other issues in the algorithm of your code but I did not examine or try to fix that.
btw:
'if any two consecutive numbers (by row) = 0'
If I understand you right, you should try 'if A(x) == 0 && A(x+1) == 0';
because '(A(x) + A(x+1) == 0)' would be true for -5 and 5, as it equals to 0. But -5 and 5 are not two consecutive zeros.
(or even look at the 'diff' function. It will return a 0 if two following numbers are the same)
To show a vectorized, more Matlab-like approach:
v = 0; % sought value
C = 2; % desired number of consecutive values in a row
consecutive = nnz(conv2(double(A==v), ones(1,C))==C)>0;
This compares each entry of A with the value v, and then applies 2D convolution with a row vector of C ones. Any C horizontally-consecutive entries of A with value v will produce an entry equal to C in the convolution result. So we check if the number of such entries is positive.

Assigning matrix elements to variables in a data set

Hello I'm new to Matlab.
I've written this script :
k2=2*pi();
z1 = 1;
z2 = 2;
z3 = 4;
for l = linspace(0,1,11)
A = [ -1 1 1 0 ; 1 z1/z2 -z1/z2 0 ; 0 exp(-i*k2*l) exp(i*k2*l) -1 ; 0 exp(- i*k2*l) -exp(i*k2*l) -z2/z3];
B = [ 1 ; 1 ; 0 ; 0];
D = inv(A);
C = mtimes(D,B) ;
display(C)
r = C(1,1); % this is supposed to set r = the 1,1 element in the matrix C
t = C(1,4); % see above
end
My idea for taking the values of r and t from C didnt appear to work. How can I do this properly?
Also I want to plot a graph of |r|,|t|, arg(r) and arg(t) for each value of l, my for loop overwrites the values of r and t? how can I either plot one point per loop or make r and t assign the new values so that they become lists of data.
Thanks a lot!
Matlab sets the first dimension of a matrix as row number (i.e. y position).
So you want t=C(4, 1), as you should see that the size of C is 4x1. As a note Matlab is quite good at suppressing singleton dimensions so you could do also do C(1) and C(4).
For your second point you want to set a particular element of r and t in each loop. This is the same as when you access at particular element of C when setting the values. For your case you can use the index l to determine the element. Remembering that in matlab arrays start at element 1 (not 0 as in many other languages). So you want something like r(l+1)=C(1); (or change l to start at 1).
In the more general case if you are not looping over an integer for some reason you may need to create a separate counter variable which you increase in the loop. Also it is good practice to preallocate such arrays when the size is known beforehand, often by r=zeros(11, 1) or similar (note: zeros(11) is an 11x11 matrix). This isn't significant in this case but can drastically increase execution time for large multi-dimensional arrays so is a good practice.

quickselect code in matlab

Let us consider following pseudo code
QuickSelect(A, k)
let r be chosen uniformly at random in the range 1 to length(A)
let pivot = A[r]
let A1, A2 be new arrays
# split into a pile A1 of small elements and A2 of big elements
for i = 1 to n
if A[i] < pivot then
append A[i] to A1
else if A[i] > pivot then
append A[i] to A2
else
# do nothing
end for
if k <= length(A1):
# it's in the pile of small elements
return QuickSelect(A1, k)
else if k > length(A) - length(A2)
# it's in the pile of big elements
return QuickSelect(A2, k - (length(A) - length(A2))
else
# it's equal to the pivot
return pivot
I have wrote following code in matlab
function []=Quickselect(A,k);
% A-unsorted array
%k-we want to return kth largest element
% let r be chosen uniformly at random in the range 1 to length(A)
i=1; %initialize index
j=1; %initialize index
n=length(A);%length of array
r=floor(1+(n-1)*rand);%random index
pivot=A(r); % choose pivot as A(r);
A1=zeros(1,n); %create additional arrays
A2=zeros(1,n);%create additional arrays
for m=1:n
if A(m)<k
A1(i)=A(m);
i=i+1;
else if A(m)>k
A2(j)=A(m);
j=j+1;
end
end
end
if k <= numel(A1)
return Quickselect(A1,k);
else if k > (length(A) - length(A2))
return Quickselect(A2, k - (length(A) - length(A2)));
else
return pivot;
end
end
end
>> A=[2 1 4 3 6 5 7 9 8 10 11 13 21 12];
>> Quickselect(A,3)
Error: File: Quickselect.m Line: 23 Column: 10
Unexpected MATLAB expression.
I dont understand reason of error, can't i use recursive property in Matlab? thanks in advance
It is not a recursivity problem, it is just wrong Matlab syntax.
In Matlab, return does not force the return of a variable, but just makes the function stop and get out. If you want to return something your function should begin with:
function [outvar]=Quickselect(A,k);
And every time you have a
return pivot;
or
return Quickselect(A1,k);
You should modify it by
outvar=pivot; % or outvar=Quickselect(A1,k);
return;
Okay, here's what's wrong with your code. I've already commented about replacing pivot with k, but after looking at the code more closely I found a few more errors. #AnderBiguri already identified a couple of problems, and I'll mention those here as well for completeness.
function []=Quickselect(A,k);
As Ander mentioned, you need the return value. I'm going to directly use pivot. And function declarations don't need a ; after them. You're effectively creating a blank first line.
function pivot = Quickselect(A,k)
You had me confused for a second with the comments:
% A-unsorted array
%k-we want to return kth largest element
% let r be chosen uniformly at random in the range 1 to length(A)
The pseudocode you gave actually finds the kth smallest element. In the list [1, 2, 3, 4, 5], 1 would be the smallest element, 2 would be the second-smallest element, and 5 would be the fifth smallest-element.
i=1; %initialize index
j=1; %initialize index
n=length(A);%length of array
r=floor(1+(n-1)*rand);%random index
I don't know why you're not using randi here. Not actually wrong the way you're doing it, but it's much clearer, much more concise with randi.
r=randi(n); % random index
Note the % create additional arrays portion here:
pivot=A(r); % choose pivot as A(r);
A1=zeros(1,n); % create additional arrays
A2=zeros(1,n); % create additional arrays
These arrays are created with the same size as A and will always have the same size as A. This was addressed by Ander in his comment and will become very important later.
Now the for loop:
for m=1:n
if A(m)<k
Your pseudocode says:
if A[i] < pivot then
pivot is the value of the element chosen as the pivot and you're trying to split A into two lists: one with elements less than the pivot, and another with elements greater than the pivot. k is the index of an element whose value you're looking for. The pseudocode correctly uses pivot, so your code should be:
if A(m)<pivot
The same thing goes for A(m)>k. It should be A(m)>pivot. Also, in Matlab, the keyword is elseif, with no space. I'm deviating a bit from my method of commenting on individual lines as they occur, but I wanted to leave the next section uninterrupted to point out something else.
A1(i)=A(m);
i=i+1;
else if A(m)>k
A2(j)=A(m);
j=j+1;
end
end
end
See that first end? What does it end? It's better if you look at your whole code, but that last end ends the for loop. The second-to-last end ends the if-elsif. The first end is wrong and should be removed. Actually, and I'm very surprised Ander didn't mention this, but if you had properly indented your code you would never have created this bug. In fact, your entire code should be re-indented consistently for this reason as well as readability. The for loop section should look like this:
for m=1:n
if A(m)<pivot
A1(i)=A(m);
i=i+1;
elseif A(m)>pivot
A2(j)=A(m);
j=j+1;
end
end
Now it's quite obvious what blocks the ends go with and how many we need.
The next line in your code is:
if k <= numel(A1)
This is the bug I referred to above that's mentioned in Ander's comment. numel(A1) will always be equal to numel(A), because that's the way you created the array. Therefore, k will always be less than or equal to the size of the input array. (Well, it should be, but there's no explicit check for that in the pseudocode or your code, but oh well.)
So where do we get the number of elements actually added to A1? Well, we go back to that for loop where we were using i as the index of the next element to be added to A1 and j as the index of the next element to be added to A2. This means that the valid length of A1 is i-1 and the valid length of A2 is j-1. So your if statement should be:
if k <= (i-1)
Next we have:
return Quickselect(A1,k);
Ander Biguri also mentioned this one. Matlab does not return values this way; you simply set the value of the return variable that was defined in the function declaration. I used pivot, so we take the value returned from our recursive call to Quickselect and assign it to our copy of pivot. When the function ends, the value of this variable automatically becomes the return value.
Now for the parameters you're passing to the recursive call. I've already said that numel(A1) == numel(A). So if you recursively call Quickselect on A1, you're not actually reducing the size of the array. We only want to pass the valid portion of A1 and since we know that it has i-1 valid elements, we can just take the first i-1 elements, i.e. A1(1:i-1).
The correct line is:
pivot = Quickselect(A1(1:i-1),k);
Now we run into the length problem again, and you've switched from using numel to using length. Not actually wrong, as far as it goes, but bad style.
else if k > (length(A) - length(A2))
return Quickselect(A2, k - (length(A) - length(A2)));
This is always zero. The length of A minus the length of something that is the same length as A is zero. The valid length of A2 is j-1. Also, we already know the size of A, it's n from way up there at the beginning. The corrected lines:
elseif k > (n - (j-1))
pivot = Quickselect(A2(1:j-1), k - (n - (j-1)));
And so we come to the end of our code:
else
return pivot;
end
end
end
As mentioned, return doesn't set any return value, it just returns from the function. Since we're at the end of the function anyway, there's no need to return. Once again, proper indentation would show you that there is an extra end here as well. We need one for the if-elseif block, and one to end the function itself, but the third one is extraneous.
If you make these changes you will have a working quickselect function.

indices must either be real positive integers or logicals. && Attempted to access f(0,0); index must be a positive integer or logical

I am new in matlab coming from c++ and trying to do 2d convolution. I have done dry run but nothing seems to go wrong but i dont know why this coming
My simple logic if value is lesser equal to zero then place zero. I am using this expression for solving that problem
i am facing 2 errors at
1)at f(q,p)=zeros(q,p);
2) at output_args(x,y)=output_args(x,y) + (W(s, t)* f(q,p));
function output_args = convo(img,k )
//skipped the portion of code---
z=s;i=t;
for x=1:row
for y=1:col
for s=s:a+2
% disp(s);
for t= t:b+2
q=z-s;
p=i-t;
if q<=0
if p <=0
f(q,p)=0; %// trying to place zero at index so help needed which is 1st error i have said
end
end
% disp(f(q,p));
output_args(x,y)=output_args(x,y) + (W(s, t)* f(q,p)); %//2nd error is comin (as i have told you above.
end
end
w=w+1;
end
z=z+1;
end
end
at console:(error occur when i apply
1) Subscript indices must either be real positive integers or logicals at f(q,p)=0
2) Attempted to access f(0,0); index must be a positive integer or logical. output_args(x,y)=output_args(x,y) + (W(s, t)* f(q,p));
so any idea?
if q<=0
if p <=0
f(q,p)=0; % p and q will always be invalid!
end
end
Well, that is begging for that error. In MATLAB, Indices must be greater than zero. While you can invert the if-condition to ensure that the index is positive, that will change the mending of your code.
if q > 0
if p > 0
f(q,p)=0; % p and q will always be valid.
end
end
If you need to index from -5 to 5 (for example) you could instead index from 1 to 11 instead. Just remember that you subtract 6 every time you display values. Alternatively, store the "real" indices in another vector.

Function: Not getting correct answer?

I'm noticing something very strange about a function I'm trying to write. My code is as follows:
function y=testfun(x)
for i=1:2
A(i*ones(2,2))=eye(2,2);
y=zeros(2,2);
y=y+eye(2,2); %+A(1*ones(2,2))
end
end
If I use y=y+eyes(2,2), then I'll get that testfun(some random number)=[1 0; 0 1]. But if I delete y=y+eyes(2,2) and type, instead, y=y+A(1*ones(2,2)), testfun(some random number) = [1 1; 1 1]. However, I would expect to get the same answer as before, [1 0; 0 1].
Is there any chance someone might know why this is? One other question I have is this: If I type A(1*ones(2,2)) in the command window, why is it that I get the error: "Undefined function 'A' for input arguments of type 'double'." Haven't I defined it?
Thanks for any help!
First thing: Matlab stores elements in column-major order. So in the first iteration (when i equals 1), the line
A(i*ones(2,2)) = eye(2,2);
is equivalent to the following statements, in this order:
A(i) = 1;
A(i) = 0;
A(i) = 0;
A(i) = 1;
Of course only the last statement is effective. So in the first iteration A is just 1. For the same reason, in the second iteration (when i equals 2) A(2) is assigned a 1 and thus A becomes [1 1].
The value of y returned by the function is that of the second iteration. In that iteration, consider the statement
y = y + A(1*ones(2,2));
Since 1*ones(2,2) is just four 1's, the expression A(1*ones(2,2)) is a matrix of four 1's, that is, ones(2,2). You are adding that to the previous value of y, which is zeros(2,2). So y becomes ones(2,2), and that value is returned by the function.