I'm trying to apply a function I wrote to each element in a matrix using arrayfun, but I'm either using the wrong function or getting my syntax wrong.
I've written a function with 3 inputs, 1 output and saved it to an m file in the same directory. I'd like to call that function, with 1 input being an element in the matrix and the 2 remaining inputs being set, and get an output matrix.
My code looks like:
fun = #(x) my_function(x,input2,input3);
B = arrayfun(#(x) fun, A)
I get the following error
Error using arrayfun function_handle output type is not currently implemented.
The correct syntax is
B = arrayfun(fun, A);
because fun is already a handle to your anonymous function.
Note that variables input1, input2 have to be defined before you define your function. The values of those variables get "hard-wired" into the function definition. If you later change those variables, that will have no effect on the function.
Related
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.
I am going to solve an inverse problem, AX=b, using conjugate gradient method in MATLAB. I want to use pcg function in MATLAB and as I know instead of matrix A I can use a function.
I have a function for example afun which has some entries. In the documents, I have seen that the afun function is entered in pcg function without entries, however, when I do the same, the error not enough input arguments appears. I use a code like this:
b = afun(ent1,ent2);
x = pcg(#afun,b,tol,max_iter);
How should I use my function in pcg?
According to the documentation, the function handle should the have the signature afun(x) and return A*x.
Your function apparently takes two inputs... You need to use a anonymous function to wrap the call, something like this:
% I dont know what these ent1/ent2 represent exactly,
% so you must complete the ".." part first
fcn = #(x) afun(x, ..)
% now you can call PCG
x = pcg(fcn, b, tol, maxiter);
There is a doc page explaining how to parameterize functions to pass extra args using function handles.
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.
Trying to find a way to call the exponentiation function ( ^ ) used in a custom function for every item in a matrix in GNU Octave.
I am quite a beginner, and I suppose that this is very simple, but I can't get it to work.
The code looks like this:
function result = the_function(the_val)
result = (the_val - 5) ^ 2
endfunction
I have tried to call it like this:
>> A = [1,2,3];
>> the_function(A);
>> arrayfun(#the_function, A);
>> A .#the_function 2;
None of these have worked (the last one I believe is simply not correct syntax), throwing the error:
error: for A^b, A must be a square matrix
This, I guess, means it is trying to square the matrix, not the elements inside of it.
How should I do this?
Thanks very much!
It is correct to call the function as the_function(A), but you have to make sure the function can handle a vector input. As you say, (the_val - 5)^2 tries to square the matrix (and it thus gives an error if the_val is not square). To compute an element-wise power you use .^ instead of ^.
So: in the definition of your function, you need to change
result = (the_val-5)^2;
to
result = (the_val-5).^2;
As an additional note, since your code as it stands does work with scalar inputs, you could also use the arrayfun approach. The correct syntax would be (remove the #):
arrayfun(the_function, A)
However, using arrayfun is usually slower than defining your function such that it works directly with vector inputs (or "vectorizing" it). So, whenever possible, vectorize your function. That's what my .^suggestion above does.
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.