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

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

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?
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

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

Thanks so much for your quick response -- I'll try this again after a dinner break.
Hi Steve,
I'm still getting the error message that says "not enough input arguments", and now an additional error message:
"Caused by:
Failure in initial objective function evaluation. FSOLVE cannot continue."
I passed into fsolve the function handle you wrote, and removed these function handles:
g = @DifferenceMap;
f = @ODE_solutions_time_T;
I wonder if fsolve doesn't like the composition g(f(x))?
First, f looks at my ode solutions gotten from ode45, gives me specific solutions (say, at time T), and then g takes differences using f's outputs.
I wonder if Walter's answer below is more suitable? Although I don't quite understand that answer yet. I'll try to get more clarity from him.
Thanks,
Please show us exactly how you call fsolve in your updated code.
Hi Steve, here's my updated code:
% Using fsolve for the Difference Mapping
% f = @ode_solutions_time_T;
% g = @DifferenceMap;
g_composed_with_f = @( xdot_0, ydot_0, thetadot_0) DifferenceMap( ode_solutions_time_T( xdot_0, ydot_0, thetadot_0 ) );
% g = @( xdot_0, ydot_0, thetadot_0) DifferenceMap( xdot_0, ydot_0, thetadot_0 );
% An initial guess at a multivariable root:
xdot_0 = 4;
ydot_0 = 5;
thetadot_0 = 0.2;
% Multivariable root finding via the fsolve algorithm:
% [xdot_0, ydot_0, thetadot_0] = fsolve( g_composed_with_f, [ xdot_0, ydot_0, thetadot_0 ] );
I didn't use the function handles with variable names f and g, if I understood your answer correctly. So, I passed in a function handle to the composition, with variable name g_composed_with_f.
I am wondering about some Mathworks documentation that I read last night about anonymous functions, namely, that they can only contain one "executable statement". Given this, I am wondering if the anonymous function g_composed_with f, which is the mapping g(x) = f(x) - x, doesn't work because first f(x) has to execute, and then f(x) - (x) executes.
What are your thoughts?
Thanks,
g_composed_with_f = @( xdot_0, ydot_0, thetadot_0) DifferenceMap( ...
ode_solutions_time_T( xdot_0, ydot_0, thetadot_0 ) );
You pass this function handle into fsolve. Does it satisfy the requirements that fsolve imposes on its first input? From its documentation page: "fun is a function that accepts a vector x and returns a vector F, the nonlinear equations evaluated at x."
Your function requires three input arguments. The examples in the description of the fun input argument all use functions with just one input argument so no, your function does not satisfy the requirements fsolve imposes.
If you know how long each of the xdot_0, ydot_0, and thetadot_0 variables are you could write another function that accepts the vector from fsolve, splits that vector apart, and calls g_composed_with_f with those three inputs. Consider this simpler example:
>> m = @(x) plus(x(1:2), x(3:4))
>> m((1:4).^2) % [1 4] + [9 16] = [10 20]
I split the four element vector [1 4 9 16] into two pieces, each two elements long, and passed those pieces into plus. In the code you posted each of those variables is a scalar, so that should be easy.
>> n = @(x) x(1)+x(2).^x(3); % equivalent to plus(x(1), power(x(2), x(3)))
>> n([2 3 5])
Hi Steve,
Ok, I'm trying this now. So, I was mistaken in assuming that fsolve would automatically treat 3 inputs as a row vector of 3 elements; instead, it sees 3 1x1 vectors as inputs.
I have a silly question: Instead of using your suggestion, why couldn't I simply bracket xdot_0, ydot_0, and thetadot_0 and input this into fsolve, so that it sees a vector input? Kind of like how you inputted [ 2 3 5 ] into the anonymous function with variable name "n". It seems that when I try this for my program, I get the red mark that says invalid Matlab syntax.
Thanks,
Hi Steve,
Also for your "n" function: Wouldn't my function f then act on n( [ 2 3 5 ] ) = 2 + 3^5, which is a scalar quantity, rather than act on the variables 2, 3, 5?
f( n( [2 3 5] ) = f( 2 + 3^5 ), it seems -- not f( 2, 3, 5), which is what I would really need -- unless there's some "breaking up" of the elements so that f evaluates the three inputs 2,3,5 that is the key point to these "plus" functions you mention.
Thanks,
Hi Steve,
When you say "accepts the vector from fsolve", did you actually mean fsolve accepts the vector?
Because there's no vector output to accept from fsolve, if it's not up and running yet.
Just making sure -- thanks.
Instead of using your suggestion, why couldn't I simply bracket xdot_0, ydot_0, and thetadot_0 and input this into fsolve, so that it sees a vector input?
Are you suggesting writing something like:
q = @([x1, x2]) x1+x2;
That's not valid MATLAB syntax. The input arguments specified in the definition of a function (anonymous or otherwise) need to be valid MATLAB identifiers (or the ~ operator to indicate MATLAB should ignore what gets passed in as that input.) [x1, x2] is a MATLAB expression consisting of two MATLAB identifiers and the horizontal concatenation operator.
If you were suggesting:
q = @(x1, x2) sin([x1, x2])
that's valid, but that doesn't solve the fsolve interface problem. q has two input arguments and fsolve calls its input with only one input.
Also for your "n" function: Wouldn't my function f then act on n( [ 2 3 5 ] ) = 2 + 3^5, which is a scalar quantity, rather than act on the variables 2, 3, 5?
Yes.
When you say "accepts the vector from fsolve", did you actually mean fsolve accepts the vector?
fsolve will call the objective function with a vector of parameter values. The objective function needs to be callable with that one vector as input.
Hi Steve,
But, using your "n" function first, then passing it into g_composed_with_f, then passing this handle to fsolve means that:
f will act on the output of the "n" function, which gives a scalar, not the 3-element vector I want f to see ... which would then mean that g will see nonsensical input.
If I can understand this point, then I might be close to debugging my fsolve program :)
Thanks,
Hi Steve,
... I might know what you mean now ...
It's simply supplying fsolve with a vector; and g_composed_with_f will evaluate the three inputs like I want them to, since it's not the case that I am coding this "n" function in the function files for f or g, too. Then the objective function, g( f(x) ), is callable by fsolve.
Will try again now.
Thanks,
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.
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)

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

Hi Walter,
I posted a new comment to Steve's answer (please see above). I wonder if your answer is more suitable, but I don't quite understand it.
I have g(f(x)), where f gives me certain ode solutions at time T.
Then g takes differences, kind of like g(x) = f(x) - x.
I passed in to fsolve the function handle that Steve suggested, and I still get the error, "not enough input arguments", and also this additional error:
"Caused by:
Failure in initial objective function evaluation. FSOLVE cannot continue."
I'm thinking that the first mapping, f, is causing some issues.
In a separate script file, I can call both f and g perfectly fine, so I know the function files for f and g are ok.
Thanks,
How many inputs does f take (number of parameters)? How many output variables does it create?
Similar question for g.
Hi Walter,
f has 3 inputs and 3 outputs, while g (composed with f) also has 3 inputs and 3 outputs.
Also, I just posted some updated code (as a comment) on Steve's answer -- please see above.
Thanks,
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))
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.

Categories

Products

Release

R2017a

Tags

Asked:

on 8 Sep 2020

Edited:

on 9 Sep 2020

Community Treasure Hunt

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

Start Hunting!