Fastest way to solve multiple nonlinear independent equations in MATLAB?
MATLAB has two methods for solving a nonlinear equation:
Therefore n
, the following methods can be used to solve a system of nonlinear independent equations :
- Use a loop to solve equations separately using
fzero
- Use a loop to solve equations separately using
fsolve
- Use
fsolve
to solve them.
My intuition would be that:
- The loop method is faster than one system for large
n
, since the complexity (calculating the gradient) is 0 (n ^ 2) - The loop can be slower for small
n
, as the loop has high overhead in MATLAB and there may be some constant startup time -
fzero
faster thanfsolve
because it is specifically designed for one non-linear equation.
Question: What's the fastest way to fix this problem? What parameters should be used to speed up the process?
Related Topics
source to share
The best approach for assessing the performance of a method is to record a test. Four cases are considered:
- loop fzero: uses a loop to solve equations separately using
fzero
- loop fsolve: uses a loop to solve equations separately with
fsolve
- default fsolve: Solves equations together as one system of equations
- independent fsolve: same as fsolve by default, but specifies that equations are independent
f = @(x) x.^2-1; % the set of non-linear equations
ns = 1:1:100; % the sizes for which the benchmark is performed
options=optimset('Display','off'); % disable displaying
figure
hold on
plot(ns, loopFSolve(f, ns, options), 'DisplayName', 'loop fsolve')
plot(ns, loopFZero(f, ns, options), 'DisplayName', 'loop fzero')
plot(ns, defaultFSsolve(f, ns, options), 'DisplayName', 'default fsolve')
plot(ns, independentFSolve(f, ns, options), 'DisplayName', 'independent fsolve')
legend ('Location', 'northwest')
function t = loopFZero(f, ns, options)
t1 = timeit(@() fzero(f, rand(1), options));
t = ns * t1;
end
function t = loopFSolve(f, ns, options)
t1 = timeit(@() fsolve(f, rand(1), options));
t = ns * t1;
end
function t = defaultFSsolve(f, ns, options)
t = zeros(size(ns));
for i=1:length(ns)
n = ns(i);
un = rand(n, 1);
t(i) = timeit(@() fsolve(f, un, options));
end
end
function t = independentFSolve(f, ns, options)
t = zeros(size(ns));
for i=1:length(ns)
n = ns(i);
un = rand(n, 1);
options.Algorithm = 'trust-region-reflective';
options.JacobPattern = speye(n);
options.PrecondBandWidth = 0;
t(i) = timeit(@() fsolve(f, un, options));
end
end
results
All figures show the computation time for the entire system as a function n
, the number of equations.
The first two digits are drawn n
up to 1000 with an interval of 100. The last two digits are drawn n
up to 100 with an interval of 1. For every second, the graph is the same as the first one, but without the fzero loop as it is much slower than the others.
- loop fsolve: don't use it, startup time is too long.
- loop fzero: you can use it for small
n
(fastest method forn < ~20
) - default fsolve: you can use it for relatively small
n
(fastest method for~20 < n < ~50
, but the difference with 2 and 3 is relatively small). - independent fsolve: you should use it for large
n
(fastest method for~50 < n
)
In general you should use an independent fsolve, only for small n
ones the fzero loop can be used, i.e. use fsolve
with the following parameters:
options.Algorithm = 'trust-region-reflective';
options.JacobPattern = speye(n);
options.PrecondBandWidth = 0;
Lazy people can just use the default fsolve as it has reasonable performance for a moderate number of equations ( n < ~200
)
Notes
- Note that the time complexity of fsolve is O (n ^ 2) by default, and the rest are O (n).
- Note that
fzero
andfsolve
may behave differently in some edge cases, fefzero
will not find a solution forx^2
when looking for a sign change location.
source to share
The file sharing service has a vectorized version of fzero:
https://www.mathworks.com/matlabcentral/fileexchange/28150-bisection-method-root-finding
In my experience, it beats the independent fsolve (using the 'JacoPattern' = speye (n) option) by an order of magnitude.
source to share