Trouble accepting input in MATLAB for anonymous functions - matlab

I have my function working if replace my input with a real function. However, when I change it like below, it asks me to input a function about like ten times and then outputs the answer.
I'm guessing this has to do with accepting functions as anonymous from a user? I'm not too sure what is going on. Thank you. This is my code:
f = #(x) input('Input a function');
A = [0 2];
z = myBisection(f,A);
With x.^2+3.*x-4 as my f function and the answer being 1.001

This is because you're not applying the right methodology for accepting inputs from input. What you are actually doing with f is that you're creating an anonymous function where if you run this, it will then ask you for input from the user. If you actually typed in this statement with your f variable as is, nothing would happen. Something would only happen if you typed in f() (or technically, f can be any input, but because the input variable for the anonymous function isn't being used in how you specified it, we can get away with specifying no inputs) in the command prompt to call this function, and then pushed ENTER. Even when you do this, the output of this function would only store a string, and you need to use this to create an anonymous function.
To fix this, what I would do is use input to store your function as a string. Take note that you need to add a second parameter for input, which is a string flag 's'. Without this, input would be expecting a number, and this obviously wouldn't work. After this, use str2func to turn this into an anonymous function, and then run your bisection method. str2func accepts in a string, and then converts that string into an actual MATLAB function and you can now use this for your purposes. By accepting your anonymous function as a string, you can place any operators you want to your heart's content, so long as the way you place them are syntactically valid. Also, make sure that your function is defined in terms of x like your example in your post.
As such do this:
funcString = input('Input a function: ', 's'); %// Make sure you specify 's'!
f = str2func(['#(x) ' funcString]);
A = [0 2];
z = myBisection(f, A);
Put this inside a .m file, then run this file. It should behave like you are expecting.

Related

How to write an anonymous function with a variable number of output arguments?

Using deal we can write anonymous functions that have multiple output arguments, like for example
minmax = #(x)deal(min(x),max(x));
[u,v] = minmax([1,2,3,4]); % outputs u = 1, v = 4
But if you want to provide a function with its gradient to the optimization function fminunc this does not work. The function fminunc calls the input function sometimes with one and sometimes with two output arguments. (EDIT: This is not true, you just have to specify whether you actually want to use the gradient or not, using e.g. optimset('SpecifyObjectiveGradient',true). Then within one call it always asks for the same number of arguments.)
We have to provide something like
function [f,g] = myFun(x)
f = x^2; % function
g = 2*x; % gradient
which can be called with one or two output arguments.
So is there a way to do the same inline without using the function keyword?
Yes there is, it involves a technique used in this question about recursive anonymous functions. First we define a helper function
helper = #(c,n)deal(c{1:n});
which accepts a cell array c of the possible outputs as well as an integer n that says how many outputs we need. To write our actual function we just need to define the cell array and pass nargout (the number of expected output arguments) to helper:
myFun = #(x)helper({x^2,2*x,2},nargout);
This now works perfectly when calling fminunc:
x = fminunc(myFun,1);
The OP's solution is good in that it's concise and useful in many cases.
However, it has one main shortcoming, in that it's less scalable than otherwise possible. This claim is made because all functions ({x^2,2*x,2}) are evaluated, regardless of whether they're needed as outputs or not - which results in "wasted" computation time and memory consumption when less than 3 outputs are requested.
In the example of this question this is not an issue because the function and its derivatives are very easy to compute and the input x is a scalar, but under different circumstances, this can be a very real issue.
I'm providing a modified version, which although uglier, avoids the aforementioned problem and is somewhat more general:
funcs_to_apply = {#(x)x.^2, #(x)2*x, #(x)2};
unpacker = #(x)deal(x{:});
myFun = #(x)unpacker(cellfun(#(c)feval(c,x),...
funcs_to_apply(1:evalin('caller','nargout')),...
'UniformOutput',false)...
);
Notes:
The additional functions I use are cellfun, evalin and feval.
The 'UniformOutput' argument was only added so that the output of cellfun is a cell (and can be "unpacked" to a comma-separated list; we could've wrapped it in num2cell instead).
The evalin trick is required since in the myFun scope we don't know how many outputs were requested from unpacker.
While eval in its various forms (here: evalin) is usually discouraged, in this case we know exactly who the caller is and that this is a safe operation.

What does this matlab statement do

I have a statement in my MATLAB program:
f = #(A)DistanceGauss(A,x_axis,Y_target,Y_initial,numOf,modus);
I understood that f is defined as the function handle to the function distancegauss which contains the parameters/arg list present inside the parentheses.
What does the variable A in #(A) do? Does it have any importance? While browsing I found that the variables within parentheses after # would be the input arguments for an anonymous function..
Can anyone explain what does that A do? Will this handle work even without that A after the # symbol ? Because it is already present as an argument to be passed after the function name.
Your code will create an anonymous function f which accepts one input A. In particular f will call the function DistanceGauss(A,x_axis,Y_target,Y_initial,numOf,modus); where the value of A is whatever you input with f(A) and the other inputs must already exist in your workspace and will be passed to the function. Note: if the other variables don't exist you should get an error when calling f.
Now a reasonable question is why would you want to do this you could just call DistanceGauss(A,x_axis,Y_target,Y_initial,numOf,modus); directly with whatever values you want, without having to worry about whether some of them exist.
There are two main reasons I can think of why you would do this (I'm sure there are others). Firstly for simplicity where your other inputs don't change and you don't want to have to keep retyping them or have users accidentally change them.
The other reason where you would want this is when optimizing/minimizing a function, for example with fminsearch. The matlab optimization functions will vary all inputs. If you want only vary some of them you can use this sort of syntax to reduce the number of input variables.
As to what A actually is in your case this will depend on what it does in DistanceGauss, which is not a standard MATLAB function so I suggest you look at the code for that.
"f(A)" or "f of A" or "The function of A" here has the handle "f"
DistanceGauss() here is another function that was defined elsewhere in your code.
You would set x_axis, Y_target, Y_initial, numOf, & modus before creating the function f. These arguments would stay the same for Function f, even if you try and set them again later.
'A' though, is different. You don't set it before you make the function. You can later operate on all values of A, such as if you plot the function or get the integral of the function. In that case, it would be performing the DistanceGauss function on every value of 'A', (though we can't see here what DistanceGauss function does. )
Anonymous function should be defined such as:
sqr = #(x) x.^2;
in which x shows the variable of the the function and there is no name for it (it is called anonymous!).
Although you can do something like this:
c = 10;
mygrid = #(x,y) ndgrid((-x:x/c:x),(-y:y/c:y));
[x,y] = mygrid(pi,2*pi);
in which you are modifying an existing function ndgrid to make a new anonymous function.
In your case also:
f = #(A)DistanceGauss(A,x_axis,Y_target,Y_initial,numOf,modus);
This is a new anonymous function by modifying the function DistanceGauss that you may want to have a single variable A.
If you remove (A) from the code, then f would be a handle to the existing function DistanceGauss:
f = #DistanceGauss;
Now you can evaluate the function simply by using the handle:
f(A,x_axis,...)

MATLAB Using fzero - returns error

I'm trying to use the MATLAB function fzero properly but my program keeps returning an error message. This is my code (made up of two m-files):
friction_zero.m
function fric_zero = friction_zero(reynolds)
fric_zero = 0.25*power(log10(5.74/(power(reynolds,0.9))),-2);
flow.m
function f = flow(fric)
f = 1/(sqrt(fric))-1.873*log10(reynolds*sqrt(fric))-233/((reynolds*sqrt(fric))^0.9)-0.2361;
f_initial = friction_zero(power(10,4));
z = fzero(#flow,f_initial)
The goal is to return z as the root for the equation specified by f when flow.m is run.
I believe I have the correct syntax as I have spent a couple of hours online looking at examples. What happens is that it returns the following error message:
"Undefined function or variable 'fric'."
(Of course it's undefined, it's the variable I'm trying to solve!)
Can someone point out to me what I've done wrong? Thanks
EDIT
Thanks to all who helped! You have assisted me to eventually figure out my problem.
I had to add another file. Here is a full summary of the completed code with output.
friction_zero.m
function fric_zero = friction_zero(re)
fric_zero = 0.25*power(log10(5.74/(power(re,0.9))),-2); %starting value for fric
flow.m
function z = flow(fric)
re = power(10,4);
z = 1/(sqrt(fric))-1.873*log10(re*sqrt(fric))-233/((re*sqrt(fric))^0.9)-0.2361;
flow2.m
f_initial = friction_zero(re); %arbitrary starting value (Reynolds)
x = #flow;
fric_root = fzero(x,f_initial)
This returns an output of:
fric_root = 0.0235
Which seems to be the correct answer (phew!)
I realised that (1) I didn't define reynolds (which is now just re) in the right place, and (2) I was trying to do too much and thus skipped out on the line x = #flow;, for some reason when I added the extra line in, MATLAB stopped complaining. Not sure why it wouldn't have just taken #flow straight into fzero().
Once again, thanks :)
You need to make sure that f is a function in your code. This is simply an expression with reynolds being a constant when it isn't defined. As such, wrap this as an anonymous function with fric as the input variable. Also, you need to make sure the output variable from your function is z, not f. Since you're solving for fric, you don't need to specify this as the input variable into flow. Also, you need to specify f as the input into fzero, not flow. flow is the name of your main function. In addition, reynolds in flow is not defined, so I'm going to assume that it's the same as what you specified to friction_zero. With these edits, try doing this:
function z = flow()
reynolds = power(10,4);
f = #(fric) 1/(sqrt(fric))-1.873*log10(reynolds*sqrt(fric))-233/((reynolds*sqrt(fric))^0.9)-0.2361;
f_initial = friction_zero(reynolds);
z = fzero(#f, f_initial); %// You're solving for `f`, not flow. flow is your function name
The reason that you have a problem is because flow is called without argument I think. You should read a little more about matlab functions. By the way, reynolds is not defined either.
I am afraid I cannot help you completely since I have not been doing fluid mechanics. However, I can tell you about functions.
A matlab function definition looks something like this:
function x0 = f(xGuess)
a = 2;
fcn =#(t) a*t.^3+t; % t must not be an input to f.
disp(fcn);
a = 3;
disp(fcn);
x0 = fsolve(fcn1,xGuess); % x0 is calculated here
The function can then ne called as myX0 = f(myGuess). When you define a matlab function with arguments and return values, you must tell matlab what to do with them. Matlab cannot guess that. In this function you tell matlab to use xGuess as an initial guess to fsolve, when solving the anonymous function fcn. Notice also that matlab does not assume that an undefined variable is an independent variable. You need to tell matlab that now I want to create an anonymous function fcn which have an independent variable t.
Observation 1: I use .^. This is since the function will take an argument an evaluate it and this argument can also be a vector. In this particulat case I want pointwise evaluation. This is not really necessary when using fsolve but it is good practice if f is not a matrix equation, since "vectorization" is often used in matlab.
Observation 2: notice that even if a changes its value the function does not change. This is since matlab passes the value of a variable when defining a function and not the variable itself. A c programmer would say that a variable is passed by its value and not by a pointer. This means that fcn is really defined as fcn = #(x) 2*t.^3+t;. Using the variable a is just a conveniance (constants can may also be complicated to find, but when found they are just a value).
Armed with this knowledge, you should be able to tackle the problem in front of you. Also, the recursive call to flow in your function will eventuallt cause a crash. When you write a function that calls itself like this you must have a stopping criterium, something to tell the program when to stop. As it is now, flow will call ifself in the last row, like z = fzero(#flow,f_initial) for 500 times and then crash. Alos it is possible as well to define functions with zero inputs:
function plancksConstant = h()
plancksConstant = 6.62606957e−34;
Where the call h or h() will return Plancks constant.
Good luck!

Matlab function handle workspace shenanigans

In short: is there an elegant way to restrict the scope of anonymous functions, or is Matlab broken in this example?
I have a function that creates a function handle to be used in a pipe network solver. It takes as input a Network state which includes information about the pipes and their connections (or edges and vertices if you must), constructs a large string which will return a large matrix when in function form and "evals" that string to create the handle.
function [Jv,...] = getPipeEquations(Network)
... %// some stuff happens here
Jv_str = ['[listConnected(~endNodes,:)',...
' .* areaPipes(~endNodes,:);\n',...
anotherLongString,']'];
Jv_str = sprintf(Jv_str); %// This makes debugging the string easier
eval(['Jv = #(v,f,rho)', Jv_str, ';']);
This function works as intended, but whenever I need to save later data structures that contain this function handle, it requires a ridiculous amount of memory (150MB) - coincidentally about as much as the entire Matlab workspace at the time of this function's creation (~150MB). The variables that this function handle requires from the getPipeEquations workspace are not particularly large, but what's even crazier is that when I examine the function handle:
>> f = functions(Network.jacobianFun)
f =
function: [1x8323 char]
type: 'anonymous'
file: '...\pkg\+adv\+pipe\getPipeEquations.m'
workspace: {2x1 cell}
...the workspace field contains everything that getPipeEquations had (which, incidentally is not the entire Matlab workspace).
If I instead move the eval statement to a sub-function in an attempt to force the scope, the handle will save much more compactly (~1MB):
function Jv = getJacobianHandle(Jv_str,listConnected,areaPipes,endNodes,D,L,g,dz)
eval(['Jv = #(v,f,rho)', Jv_str, ';']);
Is this expected behavior? Is there a more elegant way to restrict the scope of this anonymous function?
As an addendum, when I run the simulation that includes this function several times, clearing workspaces becomes painfully slow, which may or may not be related to Matlab's handling of the function and its workspace.
I can reproduce: anonymous functions for me are capturing copies of all variables in the enclosing workspace, not just those referenced in the expression of the anonymous function.
Here's a minimal repro.
function fcn = so_many_variables()
a = 1;
b = 2;
c = 3;
fcn = #(x) a+x;
a = 42;
And indeed, it captures a copy of the whole enclosing workspace.
>> f = so_many_variables;
>> f_info = functions(f);
>> f_info.workspace{1}
ans =
a: 1
>> f_info.workspace{2}
ans =
fcn: #(x)a+x
a: 1
b: 2
c: 3
This was a surprise to me at first. But it makes sense when you think about it: because of the presence of feval and eval, Matlab can't actually know at construction time what variables the anonymous function is actually going to end up referencing. So it has to capture everything in scope just in case they get referenced dynamically, like in this contrived example. This uses the value of foo but Matlab won't know that until you invoke the returned function handle.
function fcn = so_many_variables()
a = 1;
b = 2;
foo = 42;
fcn = #(x) x + eval(['f' 'oo']);
The workaround you're doing - isolating the function construction in a separate function with a minimal workspace - sounds like the right fix.
Here's a generalized way to get that restricted workspace to build your anonymous function in.
function eval_with_vars_out = eval_with_vars(eval_with_vars_expr, varargin)
% Assign variables to the local workspace so they can be captured
ewvo__reserved_names = {'varargin','eval_with_vars_out','eval_with_vars_expr','ewvo__reserved_names','ewvo_i'};
for ewvo_i = 2:nargin
if ismember(inputname(ewvo_i), ewvo__reserved_names)
error('variable name collision: %s', inputname(ewvo_i));
end
eval([ inputname(ewvo_i) ' = varargin{ewvo_i-1};']);
end
clear ewvo_i ewvo__reserved_names varargin;
% And eval the expression in that context
eval_with_vars_out = eval(eval_with_vars_expr);
The long variable names here hurt readability, but reduce the likelihood of collision with the caller's variables.
You just call eval_with_vars() instead of eval(), and pass in all the input variables as additional arguments. Then you don't have to type up a static function definition for each of your anonymous function builders. This'll work as long as you know up front what variables are actually going to be referenced, which is the same limitation as the approach with getJacobianHandle.
Jv = eval_with_vars_out(['#(v,f,rho) ' Jv_str],listConnected,areaPipes,endNodes,D,L,g,dz);
Anonymous functions capture everything within their scope and store them in the function workspace. See MATLAB documentation for anonymous functions
In particular:
"Variables specified in the body of the expression. MATLAB captures these variables and holds them constant throughout the lifetime of the function handle.
The latter variables must have a value assigned to them at the time you construct an anonymous function that uses them. Upon construction, MATLAB captures the current value for each variable specified in the body of that function. The function will continue to associate this value with the variable even if the value should change in the workspace or go out of scope."
An alternative workaround to your problem, is to use the fact that the matlab save function can be used to save only the specific variables you need. I have had issues with the save function saving way too much data (very different context from yours), but some judicial naming conventions, and use of wildcards in the variables list made all my problems go away.

To link a value in an .M-file to a .MAT-file

I'm writing a program in MATLAB to solve integrals, and I have my function in a .M-file. Now I wonder how I can write a program in the .MAT-file that lets the user set a value that exists in the both files. The .M-file looks like this:
function fh = f(y)
fh = 62.5.*(b-y).*(40-20.*exp(-(0.01.*y).*(0.01.*y)));
and as you can see, the function depends on two variables, y and b. I want the user to set b. I tried putting b = input('Type in the value of b: ') in the .M-file but for some reason the user would then have to put in the same value four times.
Can I ask for the value of b in the .MAT-file?
Firstly, m-files store code (i.e. functions), while MAT-files store data (i.e. variables). You can save workspace variables to a MAT-file using the function SAVE and load them into a workspace from a file using the function LOAD. If you have a user choose a value for b, then save it to a MAT-file ('b_value.mat', for example), you can simply load the value from the MAT-file inside your m-file function like so:
function fh = f(y)
load('b_value.mat','b');
fh = 62.5.*(b-y).*(40-20.*exp(-(0.01.*y).*(0.01.*y)));
However, this is not a very good way to handle the larger problem I think you are having. It requires that you hardcode the name of the MAT-file in your function f, plus it will give you an error if the file doesn't exist or if b isn't present in the file.
Let's address what I think the larger underlying problem is, and how to better approach a solution...
You mention that you are solving integrals, and that probably means you are performing numerical integration using one or more of the various built-in integration functions, such as QUAD. As you've noticed, using these functions requires you to supply a function for the integrand which accepts a single vector argument and returns a single vector argument.
In your case, you have other additional parameters you want to pass to the function, which is complicated by the fact that the integration functions only accept integrand functions with a single input argument. There is actually a link in the documentation for QUAD (and the other integration functions) that shows you a couple of ways you can parameterize the integrand function without adding extra input arguments by using either nested functions or anonymous functions.
As an example, I'll show you how you can do this by writing f as an anonymous function instead of an m-file function. First you would have the user choose the parameter b, then you would construct your anonymous function as follows:
b = input('Type in the value of b: ');
f = #(y) 62.5.*(b-y).*(40-20.*exp(-(0.01.*y).^2));
Note that the value of b used by the anonymous function will be fixed at what it was at the time that the function was created. If b is later changed, you would need to re-make your anonymous function so that it uses the new value.
And here's an example of how to use f in a call to QUAD:
q = quad(f,lowerLimit,upperLimit);
In your m file declare b as a global
function fh = f(y)
global b
fh = 62.5.(b-y).(40-20.*exp(-(0.01.y).(0.01.*y)));
This allows the variable to be accessed from another file without having to create another function to set the value of b. You could also add b to the arguments of your fh function.