Is this a bug in Matlab function call? - matlab

The code I am using here is for illustration of the possible bug. In the code I defined three functions as below and tried to visualize them.
The first:
$$y_1(x)=5\sin(x)$$
The second:
$$y_2(x)=12-8\cos(x)$$
The 3rd is a piecewise combination of the above two:
when x<0:
$$y_3(x)=y_1(x)$$
when x>=0:
$$y_3(x)=(y_1(x)+y_2(x))/2$$
When I run the following code in Matlab, which is saved as m2mPlot.m :
function m2mPlot
clear all
close all
clc
global a b c;
a=12;
b=8;
c=5;
t=-pi:.1:pi;
plot(t,y1(t),'b')
hold on
plot(t,y2(t),'m')
plot(t,y3(t),'r')
legend('y1','y2','y3')
function y=y1(t)
% The first function for testing
global c;
y=c*sin(t);
function y=y2(t)
% The 2nd function for testing
global a b;
y=a-b*cos(t);
function y=y3(t)
% The 3rd function for testing
if t<0 % It seems this logic value is always FALSE, why?
y=y1(t);
else
y=(y2(t)+y1(t))/2;
end
I got:
which indicates that in the third sub-function the logic expression: t<0 is always FALSE no matter what value t actually is.
Is this a bug in Matlab? How to avoid such a problem?

This is not a bug in MATLAB, you're just using it incorrectly.
You are calling y3(t) where t is a vector, i.e. t=-pi:.1:pi;. But the code for y3 uses t in a conditional, i.e. if t<0. Since the result of t<0 is a vector, and the if statement expects a scalar, it will not work as you expect. As Troy Haskin points out in the comments, from the MATLAB docs:
if expression, statements, end evaluates an expression, and executes a group of statements when the expression is true. An expression is true when its result is nonempty and contains only nonzero elements (logical or real numeric).
Otherwise, the expression is false.
Your t<0 vector contains many false values and so the if evaluates it as false. I would advise you to simply only ever give a MATLAB if a scalar.
If you want to create your y3 function in a vectorized manner try this instead:
function y=y3(t)
y=y1(t).*(t<0) + y2(t).*(t>=0);
end

Related

Write recursive sub-functions and non-recursive sub-functions in Matlab

I'm newbie to Matlab
I have an assignment :
Legendre polynomial Pn(x), n=0,1,2,. . . The recursive formula of is
Write recursive sub-functions and non-recursive sub-functions separately to find the value of the Legendre polynomial function
This is my code :
function P =Legendre(n,x)
syms x;
n = input('n=');
if n==0
P=1;
elseif n==1
P=x;
elseif n>=2
P=((2*n-1)/n)*x*Legendre(n-1)-((n-1)/n)*Legendre(n-2);
end
end
But I get an error message:
Unrecognized function or variable 'Legendre'.
Error in ti4 (line 9)
P=((2*n-1)/n)*x*Legendre(n-1)-((n-1)/n)*Legendre(n-2);
Sorry for the stupid question. Can anyone help me? Thank u so much
A few things are probably going on here.
File name needs to match function name (for the primary function)
In your case, the filename needs to be Legendre.m.
Symbolic toolbox OR do you want an answer
for most uses of this function, I would leave two full inputs, just as you have them. Bur I would remove the first two lines completely.
As it is, the first two lines will break your inputs. The value for n is reset by the input function. I'm actually not sure what happens when you declare an existing variable x, to a sym.
Input consistency
You are setting up a function with two inputs, named n and x. But when you maek your recursive calls you only pass in one variable. The easiest thing to do here is simply keep passing n in as the first input.
(Right now, you are trying to pass in x in the recursive calls, but it will be interpreted as n.)

Vectorization of function in Matlab

I'm trying to vectorize one function in Matlab, but I have a problem with assigning values.
function [val] = clenshaw(coeffs,x)
b=zeros(1,length(coeffs)+2);
for k=length(coeffs):-1:2
b(k)=coeffs(k)-b(k+2)+2*b(k+1).*x;
end
val=coeffs(1)-b(3)+b(2).*x;
The purpose of this function is to use Clenshaw's algorithm to compute a value of one polynomial with coefficients "coeffs" at point x.
It work fine when x is a single value, but I'd like it to work with vector of arguments too.
When I try to pass a vector I get an error:
Unable to perform assignment because the left
and right sides have a different number of
elements.
Error in clenshaw (line 7)
b(k)=coeffs(k)-b(k+2)+2*b(k+1).*x;
I understand that there is a problem, because I'm trying to assign vector to a scalar variable b(k).
I tried making b a matrix instead of a vector, however I still cannot get the return output I'd like to have which would be a vector of values of this function at points from vector x.
Thank you for helping and sorry if something isn't entirely clear, because English is not my native language.
The vectorized version of your function looks like this:
function [val] = clenshaw(coeffs,x)
b=zeros(length(x),length(coeffs)+2);
for k=length(coeffs):-1:2
b(:,k)=coeffs(k)-b(:,k+2)+2*b(:,k+1).*transpose(x);
end
val=coeffs(1)-b(:,3)+b(:,2).*transpose(x);
end
b needs to be a matrix. In your loop, you have to perform every operation per row of b. So you need to write b(:,k) instead of b(k). Since b(:,k) is a vector and not a scalar, you also have to be careful with the dimensions when using the .* operator. To get the correct results, you need to transpose x. The same goes for the calculation of val. If you don't like the transposition, just swap the rows and cols of b and you get this:
function [val] = clenshaw(coeffs,x)
b=zeros(length(coeffs)+2, length(x));
for k=length(coeffs):-1:2
b(k,:)=coeffs(k)-b(k+2,:)+2*b(k+1,:).*x;
end
val=coeffs(1)-b(3,:)+b(2,:).*x;
end
However, the first version returns a column vector and the second a row vector. So you might need to transpose the result if the vector type is important.

Passing vector input into MATLAB function

I am trying to write a function in MATLAB that takes 1x3 vectors as input. My code looks something like this:
function myFunction=([x1, x2, x3], [y1, y2, y3], [z1, z2, z3])
where all inputs are numbers, and then in the body of the function I perform some calculations indexing through the numerical values in the vectors. i want the vectors to be user input, so the user will enter the vectors and their components (x1, x2, etc.) into the function argument. However, I am getting an error saying "Invalid expression. When calling a function or indexing a variable, use parentheses. Otherwise, check for mismatched delimiters." Therefore I believe I either have the syntax or something else wrong. I know MATLAB is supposed to be able to take vector input in functions, so please let me know what I am doing wrong. Thanks!
What you need to do is declare your function like this:
function myFunction(x,y,z)
% your function code here
end
Then within your function you can access the individual elements of the vectors using x(1), y(2), etc.
To call the function, including whatever number you like, you can enter on the Matlab command window (for example),
myFunction([1 2 3],[4 5 6],[7 8 9]) and the code in your function will be called with the x variable set to the vector [1,2,3], the y variable set to [4,5,6] and z to [7,8,9]. The use of commas to delineate values is optional. If your function then accesses y(2) it will get the second value of the y vector which will be 5 - it is important to note that indexing in Matlab is 1-based so the 1st element of x is obtained with x(1).
If you need to return values you can use:
function [a,b,c] = myFunction(x,y,z)
Then just assign the a, b or c in your code before the end statement.
See the offical Matlab documentation for more info.
I would add that much of the advantage of matlab is dealing with data in a vectorised form, so if you can avoid splitting out into separate elements I would do so. For example, if you need to add two vecors, you could do z = [x(1)+y(1), x(2)+y(2), x(3)+y(3)], but much better (more readable, more maintainable, faster) is z=x+y.

Using fzero to solve eqn in MatLab

I hope this is the right area. I'm trying to get this code to work in MatLab.
function y=test(x)
y=-x+(B/(B-1))*(r-a)*p+(B/(B-1))*(r-a)*(b((1-(b/x)^(B-1))/r- a)+p* ((b/x)^B))/(1-(b/x)^B);
end
I then jump to the command value and type this:
B=3.0515;
b=1.18632*10^5;
a=.017;
r=.054;
p=5931617;
I then try to find the zeros of the first equation by typing this and I get errors:
solution=fzero(#test,5000000)
I'm getting the following error:
Error: File: test.m Line: 5 Column: 1 This statement is not
inside any function. (It follows the END that terminates the
definition of the function "test".)
New error
Error using fzero (line 289)
FZERO cannot continue because user supplied function_handle ==> #(x)
(test(x,B,b,a,r,p))
failed with the error below.
Subscript indices must either be real positive integers or logicals.
I would guess that this is a problem of scoping, you are defining variables (B, b, etc...) in the command line but trying to use them inside your test function where they are out of scope. You should alter your test function to take these in as parameters and then use an anonymous function so that your call to test in fsolve still only takes a single parameter:
function y=test(x, B, b, r, a, p)
y=-x+(B/(B-1))*(r-a)*p+(B/(B-1))*(r-a)*(b((1-(b/x)^(B-1))/r- a)+p* ((b/x)^B))/(1-(b/x)^B);
end
and
B=3.0515;
b=1.18632*10^5;
a=.017;
r=.054;
p=5931617;
solution=fzero(#(x)(test(x,B,b,a,r,p)),5000000)
As an aside, unless you really do mean matrix multiplication, I would suggest that you replace all your *s and /s in test with the element-wise operators .* and ./. If you are dealing with scalars, it doesn't matter now, but it makes a big difference if you later want to scale your project and need a vectorized solution.
Regarding the errors you have added to your question:
You can't put code after the end in your function file. (With the exception of local functions). Your objective function should be an .m-file containing the code for one single function.
This is because in your test function you have ...b((1-(b/x)^(B-1))... which in MATLAB means you are trying to index the variable b in which case the value of (1-(b/x)^(B-1) has to be a positive integer. I'm guess you are missing a *
Your
function y=test(x)
y=-x+(B/(B-1))*(r-a)*p+(B/(B-1))*(r-a)*(b((1-(b/x)^(B-1))/r- a)+p* ((b/x)^B))/(1-(b/x)^B);
end
cannot access variables in your workspace. You need to pass the values in somehow. You could do something like:
function y=test(x,B,b,a,r,p)
y=-x+(B/(B-1))*(r-a)*p+(B/(B-1))*(r-a)*(b((1-(b/x)^(B-1))/r- a)+p* ((b/x)^B))/(1-(b/x)^B);
end
and then you can create an implicit wrapper function:
B=3.0515;
b=1.18632*10^5;
a=.017;
r=.054;
p=5931617;
solution = fzero(#(x) test(x,B,b,a,r,p),5000000)
I haven't tested whether fzero returns sensible results, but this code shouldn't give an error.

Trick matlab into thinking gpuArray is scalar

I have following function which I would like to apply to each element:
function result = f(a, b, bs)
% Simplified code
result = a
for i=0:bs
result = dosomething(result, b(i))
end
end
% Use
arrayfun(#result, gpuArray(A), gpuArray(B), size(B));
Is there a way of 'tricking' MATLAB into thinking b is scalar for purpose of passing to function?
Unfortunately, there's currently no way to do this for two reasons: firstly, the ARRAYFUN implementation for gpuArrays always insists that inputs are either scalar or all of the same size. Secondly, the gpuArray ARRAYFUN body does not currently support either indexing or anonymous functions that refer to variables from the outer scope.
The only way to do it is to use bsxfun function:
C = bsxfun(f, A, B') % A is column vector
is more or less equivalent to
C(i,j) = f(A(i,1), B(j,1))
Other useful function is repmat.
Then the series of matrices and vectors are JITted so there is in effect no O(MN) space penalty (checked by nvidia-smi).
I'm not entirely sure what you want to do, but I suspect that you want the whole of array B to be passed into the function on each call to result. The best way of achieving this would be to use an anonymous function something like so (untested code):
arrayfun( #(a_in) result(a_in, gpuArray(B), size(B)), gpuArray(A) );
What this should do is to make an anonymous function which only takes one argument (a_in), and calls result (actually f in your function header), with the full B array, regardless of the value of a_in.
So on each iteration of arrayfun, result will be called using just one slice of A, but the whole of B.
A more syntaxically explicit way of writing the above code would be as follows:
my_anon_fun = #(a_in) result(a_in, gpuArray(B), size(B));
arrayfun( my_anon_fun , gpuArray(A) );
A disclaimer: code is untested, and I have little experience with code using gpuArray so this may not apply.