fsolve handling a composition of functions gives the error, "not enough input arguments"

6 views (last 30 days)
I'm having some trouble using fsolve on a composition of functions.
I've tried fsolve on a much simpler composition, and it worked just fine, so my code for the "real" problem probably needs to be tweaked.
My real problem starts with a Matlab function, f, that embeds nonlinear modeling code and the solutions gotten from the ode45 solver, and gives me as output only certain ODE solutions I'm interested in, e.g. solutions at the end, time T.
Then, in a separate function file, I write a function, g, that's a difference mapping that uses the outputs from f. So, it's g composed with f.
(The function g has the same inputs as the function f, and gives differences as outputs.)
Now I want to find multivariable roots of the difference mapping g, i.e. solving g = 0, using fsolve; however, I've been getting the message, "not enough input arguments".
Here's the gist of the code from my script file that's calling fsolve:
g = @DifferenceMap;
f = @ODE_solutions_time_T;
% An initial guess at a multivariable root:
xdot_0 = 5;
ydot_0 = 8;
thetadot_0 = 1;
% Multivariable root finding via the fsolve algorithm:
[ xdot_0, ydot_0, thetadot_0] = fsolve( g( f ) , [ xdot_0, ydot_0, thetadot_0 ] );
What am I missing?
Thanks,
  2 Comments
Walter Roberson
Walter Roberson on 8 Sep 2020
Could you confirm that you intend to call DifferenceMap passing in the function handle to DOE_solutions_time_T, and that you intend to have DifferenceMap return a function handle that will be invoked repeatedly by fsolve? And that whatever function handle it returns will be a function of one variable, and that DifferenceMap expects only the single function handle input?
Noob
Noob on 8 Sep 2020
Hi Walter, I think "yes" to all your questions except for the second-to-last one: DifferenceMap's function handle will be a function of, say, three variables, and output three variables. It has the same number of inputs and outputs. (Same inputs as the function, f)

Sign in to comment.

Accepted Answer

Steven Lord
Steven Lord on 8 Sep 2020
This:
g(f)
attempts to call the function handle stored in f with 0 input arguments and 1 output argument then call the function handle stored in g with the output argument from f as input. You don't want to call the function handles yourself and pass their outputs into fsolve.
This:
@(x) g(f(x))
defines an anonymous function to be called with 1 input argument. When it is called with an input argument, it calls f with that same input argument and 1 output argument. The output argument from that call to f is then passed into g as its input argument.
g = @sin;
f = @cos;
h = @(x) g(f(x));
% Try calling h
check = [h(5); sin(cos(5))]
check(1) == check(2) % true
  13 Comments
Noob
Noob on 9 Sep 2020
Edited: Noob on 9 Sep 2020
It worked!
Thanks, Steve!
Now comes the next challenge: making good initial guesses to find multivariable roots, solving g = 0.
I may at some point ask a question on this forum about how to write a loop to makes hundreds or thousands of initial guesses for this fsolve program.
Have a great night, and thanks so much for your patience.
Noob
Noob on 9 Sep 2020
Edited: Noob on 9 Sep 2020
Hi Steve,
Also, now I see that in g_composed_with_f, I was composing functions g and f, when this composition was already defined in the function file for g (the difference mapping). That was another bug too -- it would be like calling f twice, I think, and probably made Matlab throw those "initial objective function evaluation" error messages.
I simply needed an anonymous function for g, with one input.
Thanks again,

Sign in to comment.

More Answers (1)

Walter Roberson
Walter Roberson on 8 Sep 2020
Edited: Walter Roberson on 8 Sep 2020
fsolve() needs to be passed a function handle that accepts one input and returns one output.
If you have a function that returns multiple separate outputs (as opposed to returning a vector with multiple values) then to use the function with fsolve, you need to construct a true function (cannot be done with an anonymous function) that does something like
function single_output = gather_outputs(fun, varargin)
n = nargout(fun);
[outputs{1:n}] = fun(varargin{:});
single_output = cell2mat(outputs);
end
and then you would
outputs = fsolve(@(x) gather_outputs(@YourFunction, x), [ xdot_0, ydot_0, thetadot_0 ]);
xdot_0 = outputs(1);
ydot_0 = outputs(2);
thetadot_0 = outputs(3);
Notice that the output from fsolve() is not a list of variable values: the first output from fsolve is a vector of values, and the second output is a the value of the function at that final location, and the third output is the exit flag giving status information.
The function handle you pass in as the first parameter to fsolve must be of a function that expects a vector as input. If you are calling a function that expects individual parameters, then you can break them up in an anonymous function, such as
outputs = fsolve(@(x) gather_outputs(@YourFunction, x(1), x(2), x(3)), [ xdot_0, ydot_0, thetadot_0 ]);
... But if you have choice, we would recommend that you rewrite the functions to expect a vector of input and return a vector output.
  5 Comments
Walter Roberson
Walter Roberson on 9 Sep 2020
f has 3 inputs and 3 outputs
Then you must use a true function (not anonymous) similar to what I show to gather the outputs.
It is impossible in MATLAB to capture multiple output variables of a function except by using a true assignment statement. Even subsasgn() cannot do it.
The three inputs can be handled like I showed,
@(x) gather_outputs(@YourFunction, x(1), x(2), x(3))
Noob
Noob on 9 Sep 2020
Hi Walter,
My code seems to run fine now.
I'll play with the fsolve program now to see how it works, and start making some initial guesses for the program to find a multivariable root, solving g = 0.
Thanks for your help and patience,

Sign in to comment.

Tags

Products


Release

R2017a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!