fzero or fsolve ? differents results - Who is the correct ? - matlab

I have a function
b=2.02478;
g=3.45581;
s=0.6;
R=1;
p =#(r) 1 - (b./r).^2 - (g^-2)*((2/15)*(s/R)^9 *(1./(r - 1).^9 - 1./(r + 1).^9 - 9./(8*r).*(1./(r - 1).^8 - 1./(r + 1).^8)) -(s/R)^3 *(1./(r-1).^3 - 1./(r+1).^3 - 3./(2*r).*(1./(r-1).^2 - 1./(r+1).^2)));
options = optimset('Display','off');
tic
r2 = fzero(p,[1.001,100])
toc
tic
r3 = fsolve(p,[1.001,100],options)
toc
and the answer
r2 =
2.0198
Elapsed time is 0.002342 seconds.
r3 =
2.1648 2.2745
Elapsed time is 0.048991 seconds.
which is more confiable ? fzero returns different values than fsolve

You should always look at the exit flag (or output struct) of a function, especially when your result is not as expected.
This is what I get:
fzero(func,[1.00001,100]):
X = 4.9969
FVAL
EXITFLAG = 1 % fzero found a zero X.
OUTPUT.message = 'Zero found in the interval [1.00001, 100]'
fzero(func,1.1):
X = 1
FVAL = 8.2304e+136
EXITFLAG = -5 % fzero may have converged to a singular point.
OUTPUT.message = 'Current point x may be near a singular point. The interval [0.975549, 1.188] reduced to the requested tolerance and the function changes sign in the interval, but f(x) increased in magnitude as the interval reduced.'
The meaning of the exit flag is explained in the matlab documentation:
1 Function converged to a solution x.
-5 Algorithm might have converged to a singular point.
-6 fzero did not detect a sign change.
So, based on this information it is clear that the first one gives you the correct result.
Why does fzero fails
As documented in the manual, fzero calculates the zero by finding a sign change:
tries to find a point x where fun(x) = 0. This solution is where fun(x) changes sign—fzero cannot find a root of a function such as x^2.
Therefore, X = 1 is also a solution of your formulation as the sign changes at this location from +inf to -inf as can be seen on a plot:
Note that it is always a good idea to provide a search range if possible as mentioned in the manual:
Calling fzero with a finite interval guarantees fzero will return a value near a point where FUN changes sign.
Tip: Calling fzero with an interval (x0 with two elements) is often faster than calling it with a scalar x0.
Alternative: fsolve
Note that this method is developed for solving a system of multiple nonlinear equations. Therefore, it is not as efficient as fzero (~20x slower in your case). fzero uses gradient based methods (check the manual for more information), which may work better in certain situations, but may get stuck in a local extrema. In this case, the gradient of your function gives the correct direction as long as your initial value is larger than 1. So, for this specific function fsolve is somewhat more robust than fzero with a single initial value, i.e. fsolve(func, 1.1) returns the expected value.
Conclusion: In general, use fzero with a search range instead of an initial value if possible for a single variable and fsolve for multiple variables. If one method fails, you can try another method or another starting point.

As you can read in documentation:
The algorithm, which was originated by T. Dekker, uses a combination of bisection, secant, and inverse quadratic interpolation methods.
So, it is sensitive into the initial point and area which it is seeking for the solution. Hence, you have gotten different result for different initial value and scope.

Related

Indefinite integration with Matlab's Symbolic Toolbox - complex solution

I'm using Matlab 2014b. I've tried:
clear all
syms x real
assumeAlso(x>=5)
This returned:
ans =
[ 5 <= x, in(x, 'real')]
Then I tried:
int(sqrt(x^2-25)/x,x)
But this still returned a complex answer:
(x^2 - 25)^(1/2) - log(((x^2 - 25)^(1/2) + 5*i)/x)*5*i
I tried the simplify command, but still a complex answer. Now, this might be fixed in the latest version of Matlab. If so, can people let me know or offer a suggestion for getting the real answer?
The hand-calculated answer is sqrt(x^2-25)-5*asec(x/5)+C.
This behavior is present in R2017b, though when converted to floating point the imaginary components are different.
Why does this occur?
This occurs because Matlab's int function returns the full general solution when you ask for the indefinite integral. This solution is valid over the entire domain of of real values, including your restricted domain of x>=5.
With a bit of math you can show that the solution is always real for x>=5 (see complex logarithm). Or you can use more symbolic math via the isAlways function to show this:
syms x real
assume(x>=5)
y = int(sqrt(x^2-25)/x, x)
isAlways(imag(y)==0)
This returns true (logical 1). Unfortunately, Matlab's simplification routines appear to not be able to reduce this expression when assumptions are included. You might also submit this case to The MathWorks as a service request in case they'd consider improving the simplification for this and similar equations.
How can this be "fixed"?
If you want to get rid of the zero-valued imaginary part of the solution you can use sym/real:
real(y)
which returns 5*atan2(5, (x^2-25)^(1/2)) + (x^2-25)^(1/2).
Also, as #SardarUsama points out, when the full solution is converted to floating point (or variable precision) there will sometimes numeric imprecision when converting from exact symbolic form. Using the symbolic real form above should avoid this.
The answer is not really complex.
Take a look at this:
clear all; %To clear the conditions of x as real and >=5 (simple clear doesn't clear that)
syms x;
y = int(sqrt(x^2-25)/x, x)
which, as we know, gives:
y =
(x^2 - 25)^(1/2) - log(((x^2 - 25)^(1/2) + 5i)/x)*5i
Now put some real values of x≥5 to check what result it gives:
n = 1004; %We'll be putting 1000 values of x in y from 5 to 1004
yk = zeros(1000,1); %Preallocation
for k=5:n
yk(k-4) = subs(y,x,k); %Putting the value of x
end
Now let's check the imaginary part of the result we have:
>> imag(yk)
ans =
1.0e-70 *
0
0
0
0
0.028298997121333
0.028298997121333
0.028298997121333
%and so on...
Notice the multiplier 1e-70.
Let's check the maximum value of imaginary part in yk.
>> max(imag(yk))
ans =
1.131959884853339e-71
This implies that the imaginary part is extremely small and it is not a considerable amount to be worried about. Ideally it may be zero and it's coming due to imprecise calculations. Hence, it is safe to call your result real.

solving over determined non-linear equation in matlab

Actually I have to calculate values of 3 variables from probably 8 or 9 non-linear equations(may be more for accuracy).
I was using lsqnonlin and fsolve.
Using lsqnonlin, it says solver stopped prematurely (mainly due to value of iteration, funEvals and tolerance) and the output is far away from exact solution. I tried but I don't know on what basis I should set those parameters.
Using fsolve, it says no solution found.
I also used LMFnlsq and LMFsolve but it gives the output nowhere near the exact solution? I tried to change other parameters too but I could not bring those solutions to my desired values.
Is there any other way to solve these overdetermined non-linear equations?
My code till now:
x0 = [20 40 275];
eqn = #(x)[((((x(1)-Sat(1,1))^2+(x(2)-Sat(1,2))^2+(x(3)-Sat(1,3))^2))-dis(1)^2);
((((x(1)-Sat(2,1))^2+(x(2)-Sat(2,2))^2+(x(3)-Sat(2,3))^2))-dis(2)^2);
((((x(1)-Sat(3,1))^2+(x(2)-Sat(3,2))^2+(x(3)-Sat(3,3))^2))- dis(3)^2);
((((x(1)-Sat(4,1))^2+(x(2)-Sat(4,2))^2+(x(3)-Sat(4,3))^2))- dis(4))^2;
((((x(1)-Sat(5,1))^2+(x(2)-Sat(5,2))^2+(x(3)-Sat(5,3))^2))- dis(5))^2;
((((x(1)-Sat(6,1))^2+(x(2)-Sat(6,2))^2+(x(3)-Sat(6,3))^2))- dis(6))^2;
((((x(1)-Sat(7,1))^2+(x(2)-Sat(7,2))^2+(x(3)-Sat(7,3))^2))- dis(7))^2;
((((x(1)-Sat(8,1))^2+(x(2)-Sat(8,2))^2+(x(3)-Sat(8,3))^2))- dis(8))^2;
((((x(1)-Sat(9,1))^2+(x(2)-Sat(9,2))^2+(x(3)-Sat(9,3))^2))- dis(9))^2;
((((x(1)-Sat(10,1))^2+(x(2)-Sat(10,2))^2+(x(3)-Sat(10,3))^2))- dis(10))^2];
lb = [0 0 0];
ub = [100 100 10000];
options = optimoptions('lsqnonlin','MaxFunEvals',3000,'MaxIter',700,'TolFun',1e-18);%,'TolX',1);
x= lsqnonlin(eqn,x0,lb,ub,options)
**Error:**
**Solver stopped prematurely.**
lsqnonlin stopped because it exceeded the iteration limit,
options.MaxIter = 700 (the selected value).
x = 20.349 46.633 9561.5
Hoping for some suggestions!
Thanks in advance!
I usually model this explicitly:
min w'w
f_i(x) = w_i
w is a free variable
L<=x<=U
It should be easy to calculate a feasible (but non-optimal) solution in advance. If you can find a "good" initial solution that would be even better. Then use a general purpose NLP solver (e.g. fmincon) and pass on your initial feasible solution (both x and w). The best thing is to use a modeling system that allows automatic differentiation. Otherwise you should provide correct and precise gradients (and if needed second derivatives). See also the advice here.

How to get MuPAD to do some integrals for me (involving heaviside and dirac functions)?

My goal is to compute the n-fold self-convolution of a function rho(eta) where eta > 0, using MuPAD. (The background are energy densities of systems composed of many identical subsystems.) I tried to start with a simple case, but I'm already getting stuck there:
I define rho(eta) to be constantly 1 for eta > 0, so it is a Heaviside function:
rho := eta -> heaviside(eta)
and I implement the 2-fold self-convolution using a double integral and a Dirac delta function:
int(int(rho(etaA) * rho(etaB) * dirac(etaA + etaB - energy), etaB = 0..infinity), etaA=0..infinity)
with the result
so MuPAD wasn't even able to simplify the integral over a delta function and obtain a normal convolution expression; no idea what's going on with the limit here.
If I just directly enter the normal convolution expression of the function with itself
int(rho(etaA) * rho(energy - etaA), etaA = 0..infinity)
I get
again with a limit (which could be simplified to 0, or couldn't it?). The second term comes actually close to the correct answer, the heaviside just accounts for the possibility that energy may be negative. Ok, so I tell MuPAD that energy is positive:
int(rho(etaA) * rho(energy - etaA), etaA = 0..infinity) assuming energy > 0
and now MuPAD just gives me back the original unchanged integral:
Well, maybe using heaviside is the problem, and it is not strictly necessary anyway since I implement the constraint to eta > 0 through the integration limits. So I redefine
rho := eta -> 1
and use the formula with the delta function, plus the information that energy is positive:
int(int(rho(etaA) * rho(etaB) * dirac(etaA + etaB - energy), etaB = 0..infinity), etaA=0..infinity) assuming energy > 0
Guess what? Now MuPAD returns a heaviside by itself:
which is correct – but why doesn't it evaluate this integral? It's not that hard, is it?
So please anyone tell me: Why is all this happening? And how can I make it work?

Jacobi iteration doesn't end

I'm trying to implement the Jacobi iteration in MATLAB but am unable to get it to converge. I have looked online and elsewhere for working code for comparison but am unable to find any that is something similar to my code and still works. Here is what I have:
function x = Jacobi(A,b,tol,maxiter)
n = size(A,1);
xp = zeros(n,1);
x = zeros(n,1);
k=0; % number of steps
while(k<=maxiter)
k=k+1;
for i=1:n
xp(i) = 1/A(i,i)*(b(i) - A(i,1:i-1)*x(1:i-1) - A(i,i+1:n)*x(i+1:n));
end
err = norm(A*xp-b);
if(err<tol)
x=xp;
break;
end
x=xp;
end
This just blows up no matter what A and b I use. It's probably a small error I'm overlooking but I would be very grateful if anyone could explain what's wrong because this should be correct but is not so in practice.
Your code is correct. The reason why it may not seem to work is because you are specifying systems that may not converge when you are using Jacobi iterations.
To be specific (thanks to #Saraubh), this method will converge if your matrix A is strictly diagonally dominant. In other words, for each row i in your matrix, the absolute summation of all of the columns j at row i without the diagonal coefficient at i must be less than the diagonal itself. In other words:
However, there are some systems that will converge with Jacobi, even if this condition isn't satisfied, but you should use this as a general rule before trying to use Jacobi for your system. It's actually more stable if you use Gauss-Seidel. The only difference is that you are re-using the solution of x and feeding it into the other variables as you progress down the rows. To make this Gauss-Seidel, all you have to do is change one character within your for loop. Change it from this:
xp(i) = 1/A(i,i)*(b(i) - A(i,1:i-1)*x(1:i-1) - A(i,i+1:n)*x(i+1:n));
To this:
xp(i) = 1/A(i,i)*(b(i) - A(i,1:i-1)*xp(1:i-1) - A(i,i+1:n)*x(i+1:n));
**HERE**
Here are two examples that I will show you:
Where we specify a system that does not converge by Jacobi, but there is a solution. This system is not diagonally dominant.
Where we specify a system that does converge by Jacobi. Specifically, this system is diagonally dominant.
Example #1
A = [1 2 2 3; -1 4 2 7; 3 1 6 0; 1 0 3 4];
b = [0;1;-1;2];
x = Jacobi(A, b, 0.001, 40)
xtrue = A \ b
x =
1.0e+09 *
4.1567
0.8382
1.2380
1.0983
xtrue =
-0.1979
-0.7187
0.0521
0.5104
Now, if I used the Gauss-Seidel solution, this is what I get:
x =
-0.1988
-0.7190
0.0526
0.5103
Woah! It converged for Gauss-Seidel and not Jacobi, even though the system isn't diagonally dominant, I may have an explanation for that, and I'll provide later.
Example #2
A = [10 -1 2 0; -1 -11 -1 3; 2 -1 10 -1; 0 3 -1 8];
b = [6;25;-11;15];
x = Jacobi(A, b, 0.001, 40);
xtrue = A \ b
x =
0.6729
-1.5936
-1.1612
2.3275
xtrue =
0.6729
-1.5936
-1.1612
2.3274
This is what I get with Gauss-Seidel:
x =
0.6729
-1.5936
-1.1612
2.3274
This certainly converged for both, and the system is diagonally dominant.
As such, there is nothing wrong with your code. You are just specifying a system that can't be solved using Jacobi. It's better to use Gauss-Seidel for iterative methods that revolve around this kind of solving. The reason why is because you are immediately using information from the current iteration and spreading this to the rest of the variables. Jacobi does not do this, which is the reason why it diverges more quickly. For Jacobi, you can see that Example #1 failed to converge, while Example #2 did. Gauss-Seidel converged for both. In fact, when they both converge, they're quite close to the true solution.
Again, you need to make sure that your systems are diagonally dominant so you are guaranteed to have convergence. Not enforcing this rule... well... you'll be taking a risk as it may or may not converge.
Good luck!
Though this does not point out the problem in your code, I believe that you are looking for the Numerical Methods: Jacobi File Exchange Submission.
%JACOBI Jacobi iteration for solving a linear system.
% Sample call
% [X,dX] = jacobi(A,B,P,delta,max1)
% [X,dX,Z] = jacobi(A,B,P,delta,max1)
It seems to do exactly what you describe.
As others have pointed out that not all systems are convergent using Jacobi method, but they do not point out why? Actually only a small sub-set of systems converge with Jacobi method.
The convergence criteria is that the "sum of all the coefficients (non-diagonal) in a row" must be lesser than the "coefficient at the diagonal position in that row". This criteria must be satisfied by all the rows. You can read more at: Jacobi Method Convergence
Before you decide to use Jacobi method, you must see whether this criteria is satisfied by the numerical method or not. The Gauss-Seidel method has a slightly more relaxed convergence criteria which allows you to use it for most of the Finite Difference type numerical methods.

Gauss-Seidel Method exceeds Machine Numbers?

Happy New Year everyone! :)
I'm writing a Gauss-Seidel function in Matlab and I'm encountering some problems.
The iteration must stop when we reach 6 decimal digits of precision. It means that the infinite norm (asked to use it) of x-xprevious must be less than 0.5*10^(-6).
Firstly, here's my function:
function [x] = ex1_3(A,b)
format long
sizeA=size(A,1);
x=zeros(sizeA,1);
%Just a check for the conditions of the Gauss-Seidel Method
for i=1:sizeA
sum=0;
for j=1:sizeA
if i~=j
sum=sum+A(i,j);
end
end
if A(i,i)<sum
fprintf('\nGauss-Seidel''s conditions not met!\n');
return
end
end
%Actual Gauss-Seidel Method
max_temp=10^(-6); %Pass first iteration
while max_temp>(0.5*10^(-6))
xprevious=x;
for i=1:sizeA
x(i,1)=b(i,1);
for j=1:sizeA
if i~=j
x(i,1)=x(i,1)-A(i,j)*x(j,1);
end
end
x(i,1)=x(i,1)/A(i,i);
end
x
%Calculating infinite norm of vector x-xprevious
temp=x-xprevious;
max_temp=temp(1,1);
for i=2:sizeA
if abs(temp(i,1))>max_temp
max_temp=abs(temp(i,1));
end
end
end
And now the problems! When I call the function for a 3x3 array, I think it works. However, when I call it for a 10x10 array x becomes Inf (I guess it's out of machine numbers limits). Is there anything I can do to prevent this, except for changing the infinite norm and the 6 decimal digits precision (I must use these two, because my tutor told me so) ?
In the array I use (which was given to me) the entries outside the diagonal are -1 and the ones on the diagonal are 3. b is like this b=[2;1;1;1;1;1;1;1;1;2] (for n=10)
Your condition of the Gauss-Seidel Method is not correct:
D=diag(diag(A));
L=-tril(A,-1);U=-triu(A,1);
B=(D-L)\U;
R = max(abs(eig(B)));
if R>=1
fprintf('\nGauss-Seidel''s conditions not met!\n');
return
end
R is called spectral radius of iterative matrix B. It has to be less than 1 that Gauss-Seidel converges. Actually the matrix A in your test case has the R=1.8092, thus Gauss-Seidel method won't converge.
Check this slide from page 18 for more details.
EDIT
According to #LutzL's comment, you may use Gershgorin circle theorem to estimate the eigenvalue rather than calculate them with computational cost.