11 views (last 30 days)

Show older comments

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,

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

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.

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

Start Hunting!